You are on page 1of 483

An Introdu

tion to Programming through C++


Abhiram Ranade


Do not distribute

Abhiram Ranade, 2013


Contents

Prefa e 14
0.1 Graphi s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
0.2 First day/ rst month blues . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
0.3 Obje t oriented programming . . . . . . . . . . . . . . . . . . . . . . . . . . 17
0.4 Fitting the book into a urri ulum . . . . . . . . . . . . . . . . . . . . . . . 17
1 Introdu tion 18
1.1 A simple program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.1.1 Exe uting the program . . . . . . . . . . . . . . . . . . . . . . . . . . 20
1.2 Remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.2.1 Exe ution order . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.3 Repeating a blo k of ommands . . . . . . . . . . . . . . . . . . . . . . . . . 22
1.3.1 Drawing any regular polygon . . . . . . . . . . . . . . . . . . . . . . 22
1.3.2 Repeat within a repeat . . . . . . . . . . . . . . . . . . . . . . . . . . 24
1.4 Some useful turtle ommands . . . . . . . . . . . . . . . . . . . . . . . . . . 24
1.5 Numeri al fun tions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
1.6 Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
1.7 Computation without graphi s . . . . . . . . . . . . . . . . . . . . . . . . . . 27
1.8 Con luding Remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
1.8.1 Graphi s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
1.8.2 A note regarding the exer ises . . . . . . . . . . . . . . . . . . . . . . 29
1.9 Exer ises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
2 A bird's eye view 31
2.1 Problem solving using omputers . . . . . . . . . . . . . . . . . . . . . . . . 31
2.1.1 Algorithms and programs . . . . . . . . . . . . . . . . . . . . . . . . 33
2.2 Basi prin iples of digital ir uits . . . . . . . . . . . . . . . . . . . . . . . . 34
2.3 Number representation formats . . . . . . . . . . . . . . . . . . . . . . . . . 35
2.3.1 Unsigned integer representation . . . . . . . . . . . . . . . . . . . . . 35
2.3.2 Signed integers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
2.3.3 Floating point representations . . . . . . . . . . . . . . . . . . . . . . 36
2.4 Organization of a omputer . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
2.5 Main memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
2.5.1 Addresses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
2.5.2 Ports and operations . . . . . . . . . . . . . . . . . . . . . . . . . . . 39

1
Abhiram Ranade, 2013. Do not distribute 2
2.6 The arithmeti unit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
2.7 Input-Output Devi es . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
2.7.1 Keyboard . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
2.7.2 Display . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
2.7.3 Disks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
2.7.4 Remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
2.8 The Control Unit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
2.8.1 Control Flow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
2.9 High level programming languages . . . . . . . . . . . . . . . . . . . . . . . . 44
2.10 Con luding Remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
2.11 Exer ises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
3 Numbers 46
3.1 Variables and data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
3.1.1 Identi ers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
3.1.2 Literals and variable initialization . . . . . . . . . . . . . . . . . . . . 49
3.1.3 The onst keyword . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
3.1.4 Reading data into a variable . . . . . . . . . . . . . . . . . . . . . . . 51
3.1.5 Printing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
3.1.6 Exa t representational parameters . . . . . . . . . . . . . . . . . . . . 52
3.2 Arithmeti and assignment . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
3.2.1 Integer division and the modulo operator % . . . . . . . . . . . . . . . 54
3.2.2 Subtleties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
3.2.3 Over ow and arithmeti errors . . . . . . . . . . . . . . . . . . . . . . 56
3.2.4 In nity and not a number . . . . . . . . . . . . . . . . . . . . . . . . 57
3.2.5 Expli it type onversion . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.2.6 Assignment expression . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.3 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
3.4 Assignment with repeat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
3.4.1 Programming Idioms . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
3.4.2 Combining sequen e generation and a umulation . . . . . . . . . . . 62
3.5 Some operators inspired by the idioms . . . . . . . . . . . . . . . . . . . . . 62
3.5.1 In rement and de rement operators . . . . . . . . . . . . . . . . . . . 63
3.5.2 Compound assignment operators . . . . . . . . . . . . . . . . . . . . 63
3.6 Blo ks and variable de nitions . . . . . . . . . . . . . . . . . . . . . . . . . . 64
3.6.1 Blo k . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
3.6.2 General prin iple 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
3.6.3 General prin iple 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
3.7 Con luding remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
3.8 Exer ises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
4 A program design example 71
4.1 Spe i ation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
4.1.1 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
4.2 Program design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Abhiram Ranade, 2013. Do not distribute 3
4.2.1 Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
4.2.2 Corre tness Proof . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
4.2.3 Invariants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
4.3 Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
4.4 Comments in the ode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
4.5 Con luding remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
4.5.1 A note on programming exer ises . . . . . . . . . . . . . . . . . . . . 78
4.6 Exer ises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
5 Simple pp graphi s 80
5.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
5.1.1 y axis goes downward! . . . . . . . . . . . . . . . . . . . . . . . . . . 81
5.2 Multiple Turtles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
5.3 Other shapes besides turtles . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
5.3.1 Cir les . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
5.3.2 Re tangles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
5.3.3 Lines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
5.3.4 Text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
5.4 Commands allowed on shapes . . . . . . . . . . . . . . . . . . . . . . . . . . 83
5.4.1 Rotation in radians . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
5.4.2 Tra king a shape . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
5.4.3 Imprinting on the anvas . . . . . . . . . . . . . . . . . . . . . . . . . 84
5.4.4 Resetting a shape . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
5.5 Cli king on the anvas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
5.6 Proje tile Motion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
5.7 Best t straight line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
5.8 Con luding Remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
5.9 Exer ises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
6 Conditional Exe ution 91
6.1 The If statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
6.2 Blo ks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
6.3 Other forms of the if statement . . . . . . . . . . . . . . . . . . . . . . . . . 95
6.4 A di erent turtle ontroller . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
6.4.1 \Buttons" on the anvas . . . . . . . . . . . . . . . . . . . . . . . . . 99
6.5 The swit h statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
6.6 Conditional Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
6.7 Logi al Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
6.7.1 Reasoning about logi al data . . . . . . . . . . . . . . . . . . . . . . 103
6.7.2 Determining whether a number is prime . . . . . . . . . . . . . . . . 104
6.8 Remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
6.9 Exer ises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
Abhiram Ranade, 2013. Do not distribute 4
7 Loops 110
7.1 The while statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
7.1.1 Counting the number of digits . . . . . . . . . . . . . . . . . . . . . . 112
7.1.2 Mark averaging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
7.2 The break statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
7.3 The ontinue statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
7.4 The do while statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
7.5 The for statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
7.5.1 Variables de ned in initialization . . . . . . . . . . . . . . . . . . 120
7.5.2 Break and ontinue . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
7.5.3 Style issue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
7.5.4 Determining if a number is prime . . . . . . . . . . . . . . . . . . . . 121
7.6 Un ommon ways of using for . . . . . . . . . . . . . . . . . . . . . . . . . . 121
7.6.1 Comma separated assignments . . . . . . . . . . . . . . . . . . . . . . 122
7.6.2 Input in initialization and update . . . . . . . . . . . . . . . . . 122
7.7 The Greatest Common Divisor . . . . . . . . . . . . . . . . . . . . . . . . . . 123
7.8 Corre tness of looping programs . . . . . . . . . . . . . . . . . . . . . . . . . 124
7.8.1 Loop Invariant . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
7.8.2 Potential . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
7.8.3 Corre tness . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
7.8.4 Additional observations regarding the GCD program . . . . . . . . . 126
7.8.5 Corre tness of other programs . . . . . . . . . . . . . . . . . . . . . . 126
7.9 Remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
8 Computing ommon mathemati al fun tions 129
8.1 Taylor series . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
8.1.1 Sine of an angle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
8.1.2 Natural log . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
8.1.3 Some general remarks . . . . . . . . . . . . . . . . . . . . . . . . . . 132
8.2 Numeri al integration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
8.3 Bise tion method for nding roots . . . . . . . . . . . . . . . . . . . . . . . . 134
8.4 Newton Raphson Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
8.5 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
8.5.1 Mathemati al ideas . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
8.5.2 Programming ideas . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
9 Fun tions 142
9.1 De ning a fun tion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
9.1.1 Exe ution: all by value . . . . . . . . . . . . . . . . . . . . . . . . . 144
9.1.2 Names of parameters and lo al variables . . . . . . . . . . . . . . . . 145
9.2 Nested fun tion alls: LCM . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
9.3 The ontra t view of fun tion exe ution . . . . . . . . . . . . . . . . . . . . . 147
9.3.1 Fun tion spe i ation . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
9.4 Fun tions that do not return values . . . . . . . . . . . . . . . . . . . . . . . 148
9.5 A text drawing program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
Abhiram Ranade, 2013. Do not distribute 5
9.6 Some diÆ ulties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
9.7 Call by referen e . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
9.7.1 Remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
9.7.2 Referen e variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
9.8 Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
9.8.1 \Address of" operator & . . . . . . . . . . . . . . . . . . . . . . . . . 155
9.8.2 Pointer variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
9.8.3 Dereferen ing operator * . . . . . . . . . . . . . . . . . . . . . . . . . 156
9.8.4 Use in fun tions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
9.8.5 Referen e vs. Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . 158
9.9 Returning referen es and pointers . . . . . . . . . . . . . . . . . . . . . . . . 159
9.10 Default values of parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
9.11 Fun tion overloading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
9.12 Fun tion templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
10 Re ursive Fun tions 164
10.1 Eu lid's algorithm for GCD . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
10.1.1 Exe ution of re ursive g d . . . . . . . . . . . . . . . . . . . . . . . . 166
10.1.2 Interpretation of re ursive programs . . . . . . . . . . . . . . . . . . . 167
10.1.3 Corre tness of re ursive programs . . . . . . . . . . . . . . . . . . . . 167
10.2 Re ursive pi tures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
10.2.1 Trees without using a turtle . . . . . . . . . . . . . . . . . . . . . . . 171
10.2.2 Hilbert spa e lling urve . . . . . . . . . . . . . . . . . . . . . . . . 172
10.3 Virahanka numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
10.3.1 Using a loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
10.3.2 Histori al Remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
10.4 The game of Nim . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
10.4.1 Remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
10.5 Con luding remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
11 Program organization and fun tions 185
11.1 The main program is a fun tion! . . . . . . . . . . . . . . . . . . . . . . . . . 186
11.2 Organizing fun tions into les . . . . . . . . . . . . . . . . . . . . . . . . . . 186
11.2.1 Fun tion De laration or Prototype . . . . . . . . . . . . . . . . . . . 186
11.2.2 Splitting a program into multiple les . . . . . . . . . . . . . . . . . . 187
11.2.3 Separate ompilation and obje t modules . . . . . . . . . . . . . . . . 187
11.2.4 Header les . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189
11.2.5 Header guards . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
11.2.6 Pa kaging software . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
11.2.7 Forward de laration . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
11.2.8 Fun tion templates and header les . . . . . . . . . . . . . . . . . . . 191
11.3 Namespa es . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
11.3.1 De nition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
11.3.2 The using de laration and dire tive . . . . . . . . . . . . . . . . . . . 193
11.3.3 The global namespa e . . . . . . . . . . . . . . . . . . . . . . . . . . 193
Abhiram Ranade, 2013. Do not distribute 6
11.3.4 Unnamed namespa es . . . . . . . . . . . . . . . . . . . . . . . . . . 194
11.3.5 Namespa es and header les . . . . . . . . . . . . . . . . . . . . . . . 194
11.4 Global variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
11.5 Two important namespa es . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
11.6 C++ without simple pp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
11.7 Fun tion Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
11.7.1 Some simpli ations . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
11.8 Con luding remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
11.8.1 Fun tion size and readability . . . . . . . . . . . . . . . . . . . . . . . 200
11.9 Exer ises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
12 Pra ti e of programming: some tips and tools 202
12.1 Clarity of spe i ation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
12.2 Input-output examples and testing . . . . . . . . . . . . . . . . . . . . . . . 204
12.3 Input/output redire tion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206
12.4 Algorithm design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206
12.4.1 Mentally exe ute the program . . . . . . . . . . . . . . . . . . . . . . 208
12.4.2 Test ases for ode overage . . . . . . . . . . . . . . . . . . . . . . . 208
12.5 Assertions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208
12.5.1 Disabling assertions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
12.6 Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
12.6.1 Debuggers and IDEs . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
12.6.2 End of le and data input errors . . . . . . . . . . . . . . . . . . . . . 211
12.6.3 Aside: Input-Output expressions . . . . . . . . . . . . . . . . . . . . 211
12.7 Random numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212
12.7.1 The randuv fun tion in simple pp . . . . . . . . . . . . . . . . . . . 213
12.8 Con luding remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
12.9 Exer ises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214
13 Arrays 215
13.1 Array: Colle tion of variables . . . . . . . . . . . . . . . . . . . . . . . . . . 215
13.1.1 Array element operations . . . . . . . . . . . . . . . . . . . . . . . . . 216
13.1.2 A eptable range for the index . . . . . . . . . . . . . . . . . . . . . . 217
13.1.3 Initializing arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
13.2 Examples of use . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218
13.2.1 Notation for subarrays . . . . . . . . . . . . . . . . . . . . . . . . . . 218
13.2.2 A marks display program . . . . . . . . . . . . . . . . . . . . . . . . . 218
13.2.3 Who got the highest? . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
13.2.4 General roll numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
13.2.5 Histogram . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
13.2.6 A taxi dispat h program . . . . . . . . . . . . . . . . . . . . . . . . . 223
13.2.7 A geometri problem . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
13.3 The inside story . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227
13.3.1 Out of range array indi es . . . . . . . . . . . . . . . . . . . . . . . . 228
13.3.2 The array name by itself . . . . . . . . . . . . . . . . . . . . . . . . . 228
Abhiram Ranade, 2013. Do not distribute 7
13.3.3 [℄ as an operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
13.4 Fun tion Calls involving arrays . . . . . . . . . . . . . . . . . . . . . . . . . 231
13.4.1 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232
13.4.2 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
13.5 Sele tion sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
13.5.1 Estimate of time taken . . . . . . . . . . . . . . . . . . . . . . . . . . 234
13.6 Representing Polynomials . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235
13.7 Array Length and onst values . . . . . . . . . . . . . . . . . . . . . . . . . 236
13.7.1 Why onst de larations? . . . . . . . . . . . . . . . . . . . . . . . . . 237
13.7.2 What we use in this book . . . . . . . . . . . . . . . . . . . . . . . . 238
13.8 Con luding remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238
13.9 Exer ises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238
14 More on arrays 243
14.1 Chara ter strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244
14.1.1 Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244
14.1.2 Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245
14.1.3 Chara ter array pro essing . . . . . . . . . . . . . . . . . . . . . . . . 246
14.1.4 Address arithmeti . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
14.2 Two dimensional Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249
14.2.1 Linear simultaneous equations . . . . . . . . . . . . . . . . . . . . . . 250
14.2.2 Two dimensional har arrays . . . . . . . . . . . . . . . . . . . . . . 251
14.2.3 Passing 2 dimensional arrays to fun tions . . . . . . . . . . . . . . . . 252
14.2.4 Drawing polygons in simple pp . . . . . . . . . . . . . . . . . . . . . 253
14.3 Arrays of Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253
14.3.1 Command line arguments to main . . . . . . . . . . . . . . . . . . . . 254
14.4 Binary sear h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255
14.4.1 Estimate of time taken . . . . . . . . . . . . . . . . . . . . . . . . . . 257
14.5 Merge sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
14.5.1 A merging algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . 258
14.5.2 Mergesort algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . 258
14.6 Exer ises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
15 Stru tures 264
15.1 Basi s of stru tures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264
15.1.1 Visibility of stru ture types and stru ture variables . . . . . . . . . . 267
15.1.2 Arrays of stru tures . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267
15.1.3 Pointers to Stru tures and -> . . . . . . . . . . . . . . . . . . . . . . 268
15.1.4 Pointers as stru ture members . . . . . . . . . . . . . . . . . . . . . . 268
15.1.5 Linked stru tures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
15.2 Stru tures and fun tions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
15.2.1 onst referen e parameters . . . . . . . . . . . . . . . . . . . . . . . 271
15.2.2 Passing pointers to stru tures . . . . . . . . . . . . . . . . . . . . . . 271
15.3 Representing ve tors from physi s . . . . . . . . . . . . . . . . . . . . . . . . 271
15.4 Taxi dispat h revisited . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
Abhiram Ranade, 2013. Do not distribute 8
15.5 Member Fun tions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274
15.5.1 Referen e parameters and onst . . . . . . . . . . . . . . . . . . . . . 277
15.6 Mis ellaneous features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
15.6.1 Stati data members . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
15.6.2 Stati member fun tions . . . . . . . . . . . . . . . . . . . . . . . . . 278
15.6.3 The this pointer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
15.6.4 Default values to parameters . . . . . . . . . . . . . . . . . . . . . . . 279
15.7 Exer ises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
16 Classes: stru tures with a personality 281
16.1 Constru tors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282
16.1.1 Calling the onstru tor expli itly . . . . . . . . . . . . . . . . . . . . 284
16.1.2 Default values to parameters . . . . . . . . . . . . . . . . . . . . . . . 284
16.1.3 \Default" Constru tor . . . . . . . . . . . . . . . . . . . . . . . . . . 285
16.1.4 Constru tors of nested stru tures . . . . . . . . . . . . . . . . . . . . 285
16.1.5 Initialization lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286
16.1.6 Constant members . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287
16.2 The opy onstru tor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287
16.3 Destru tors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288
16.4 Overloading operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289
16.5 Another overloading me hanism . . . . . . . . . . . . . . . . . . . . . . . . . 290
16.6 Overloading assignment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
16.7 A ess Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292
16.7.1 A essor and mutator fun tions . . . . . . . . . . . . . . . . . . . . . 292
16.7.2 Prohibiting ertain operations . . . . . . . . . . . . . . . . . . . . . . 293
16.7.3 Friends . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293
16.8 Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294
16.9 Header and implementation les . . . . . . . . . . . . . . . . . . . . . . . . . 294
16.9.1 Separate ompilation . . . . . . . . . . . . . . . . . . . . . . . . . . . 296
16.9.2 Remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296
16.10Template lasses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296
16.11Some lasses you have already used, almost . . . . . . . . . . . . . . . . . . . 297
16.11.1Graphi s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297
16.11.2Standard input and output . . . . . . . . . . . . . . . . . . . . . . . . 298
16.11.3File I/O . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298
16.12Remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299
16.13Exer ises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299
17 A proje t: osmologi al simulation 301
17.1 Mathemati s of Cosmologi al simulation . . . . . . . . . . . . . . . . . . . . 301
17.2 Overview of the program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304
17.2.1 Main Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305
17.3 The lass Star . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
17.4 Compiling and exe ution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308
17.5 Con luding Remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309
Abhiram Ranade, 2013. Do not distribute 9
17.6 Exer ises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310
18 Graphi s Events 311
18.1 Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311
18.1.1 Event obje ts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311
18.1.2 Waiting for events . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312
18.2 Che king for events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312
18.2.1 Mouse button press events . . . . . . . . . . . . . . . . . . . . . . . . 312
18.2.2 Mouse drag events . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312
18.2.3 Key press events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
18.3 A drawing program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
18.4 A rudimentary Snake game . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
18.4.1 Spe i ation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314
18.4.2 Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314
18.4.3 User intera tion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314
18.5 Exer ises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316
19 Representing variable length entities 317
19.1 The Heap Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318
19.1.1 A detailed example . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
19.1.2 Lifetime and a essibility . . . . . . . . . . . . . . . . . . . . . . . . . 320
19.2 Representing text: a preliminary implementation . . . . . . . . . . . . . . . 320
19.2.1 The basi storage ideas . . . . . . . . . . . . . . . . . . . . . . . . . . 321
19.2.2 Constru tor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321
19.2.3 The print member fun tion . . . . . . . . . . . . . . . . . . . . . . . 322
19.2.4 Assignments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322
19.2.5 De ning operator + . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323
19.3 Advan ed topi s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324
19.3.1 Destru tors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324
19.3.2 Copy onstru tor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 325
19.3.3 The [℄ operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326
19.3.4 An improved assignment operator . . . . . . . . . . . . . . . . . . . . 326
19.3.5 Use . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326
19.4 Remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327
19.4.1 Class invariants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327
19.5 Exer ises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329
20 The standard library 332
20.1 The string lass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332
20.1.1 Passing strings to fun tions . . . . . . . . . . . . . . . . . . . . . . . 334
20.1.2 A detailed example . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334
20.2 The template lass ve tor . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334
20.2.1 Inserting and deleting elements . . . . . . . . . . . . . . . . . . . . . 335
20.2.2 Index bounds he king . . . . . . . . . . . . . . . . . . . . . . . . . . 335
20.2.3 Fun tions on ve tors . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
20.2.4 Ve tors of user de ned data types . . . . . . . . . . . . . . . . . . . . 336
Abhiram Ranade, 2013. Do not distribute 10
20.2.5 Multidimensional ve tors . . . . . . . . . . . . . . . . . . . . . . . . . 336
20.2.6 A matrix lass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337
20.3 Sorting a ve tor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338
20.4 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
20.4.1 Marks display variation 1 . . . . . . . . . . . . . . . . . . . . . . . . 339
20.4.2 Marks display variation 2 . . . . . . . . . . . . . . . . . . . . . . . . 339
20.4.3 Marks display variation 3 . . . . . . . . . . . . . . . . . . . . . . . . 340
20.5 The map template lass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341
20.5.1 Marks display variation 4 . . . . . . . . . . . . . . . . . . . . . . . . 343
20.5.2 Time to a ess a map . . . . . . . . . . . . . . . . . . . . . . . . . . . 345
20.6 Containers and Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345
20.6.1 Finding and deleting map elements . . . . . . . . . . . . . . . . . . . 347
20.6.2 Inserting and deleting ve tor elements . . . . . . . . . . . . . . . . . 348
20.7 Other ontainers in the standard library . . . . . . . . . . . . . . . . . . . . 348
20.8 The typedef statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349
20.8.1 More general form . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349
20.9 Remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350
20.10Exer ises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350
21 Representing networks of entities 353
21.1 Graphs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353
21.1.1 Adja en y lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354
21.1.2 Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355
21.1.3 Array indi es rather than pointers . . . . . . . . . . . . . . . . . . . . 355
21.1.4 Edges represented expli itly . . . . . . . . . . . . . . . . . . . . . . . 356
21.2 Adja en y matrix representation . . . . . . . . . . . . . . . . . . . . . . . . . 356
21.3 Sur ng on the internet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 357
21.4 Cir uits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359
21.5 Edge list representation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362
21.6 Auxiliary data stru tures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362
21.7 Remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362
21.8 Exer ises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362
22 Stru tural re ursion 364
22.1 Layout of mathemati al formulae . . . . . . . . . . . . . . . . . . . . . . . . 365
22.1.1 Input format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365
22.1.2 Layout \by hand" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 366
22.1.3 Representing mathemati al formulae . . . . . . . . . . . . . . . . . . 368
22.1.4 Reading in a formula . . . . . . . . . . . . . . . . . . . . . . . . . . . 370
22.1.5 Drawing the formula: overview . . . . . . . . . . . . . . . . . . . . . 371
22.1.6 The omplete main program . . . . . . . . . . . . . . . . . . . . . . . 375
22.1.7 Remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 375
22.2 Maintaining an ordered set . . . . . . . . . . . . . . . . . . . . . . . . . . . . 375
22.2.1 A sear h tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 376
22.2.2 The general idea . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377
Abhiram Ranade, 2013. Do not distribute 11
22.2.3 The implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . 378
22.2.4 A note about organizing the program . . . . . . . . . . . . . . . . . . 380
22.2.5 On the eÆ ien y of sear h trees . . . . . . . . . . . . . . . . . . . . . 380
22.2.6 Balan ing the sear h tree . . . . . . . . . . . . . . . . . . . . . . . . . 382
22.2.7 Sear h trees and maps . . . . . . . . . . . . . . . . . . . . . . . . . . . 382
22.3 Exer ises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 382
23 Inheritan e 386
23.1 Turtles with an odometer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387
23.1.1 Implementation using Composition . . . . . . . . . . . . . . . . . . . 387
23.1.2 Implementation using Inheritan e . . . . . . . . . . . . . . . . . . . . 388
23.2 General prin iples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 389
23.2.1 A ess rules and prote ted members . . . . . . . . . . . . . . . . . . 390
23.2.2 Constru tors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392
23.2.3 Destru tors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393
23.2.4 Basi operations on sub lass obje ts . . . . . . . . . . . . . . . . . . 393
23.2.5 The type of a sub lass obje t . . . . . . . . . . . . . . . . . . . . . . 393
23.2.6 Assignments mixing super lass and sub lass obje ts . . . . . . . . . . 393
23.3 Polymorphism and virtual fun tions . . . . . . . . . . . . . . . . . . . . . . . 395
23.3.1 Virtual Destru tor . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396
23.4 Program to print past tense . . . . . . . . . . . . . . . . . . . . . . . . . . . 397
23.5 Abstra t Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399
23.6 Multiple inheritan e . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400
23.6.1 Diamond Inheritan e . . . . . . . . . . . . . . . . . . . . . . . . . . . 401
23.7 Types of inheritan e . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401
23.8 Remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402
23.9 Exer ises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402
24 Inheritan e based design 405
24.1 Formula drawing revisited . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406
24.1.1 Basi design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406
24.1.2 Comparison of the two approa hes . . . . . . . . . . . . . . . . . . . 409
24.1.3 Adding exponential expressions . . . . . . . . . . . . . . . . . . . . . 410
24.2 The simple pp graphi s system . . . . . . . . . . . . . . . . . . . . . . . . . 411
24.3 Composite graphi s obje ts . . . . . . . . . . . . . . . . . . . . . . . . . . . 414
24.3.1 Ownership . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414
24.3.2 The Composite lass onstru tor . . . . . . . . . . . . . . . . . . . . 415
24.3.3 A Car lass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415
24.3.4 Frames . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417
24.3.5 Main program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417
25 Dis rete event simulation 419
25.1 Dis rete event simulation overview . . . . . . . . . . . . . . . . . . . . . . . 420
25.1.1 Dis rete time systems . . . . . . . . . . . . . . . . . . . . . . . . . . . 420
25.1.2 Evolution of a dis rete time system . . . . . . . . . . . . . . . . . . . 421
25.1.3 Implementing a dis rete time system . . . . . . . . . . . . . . . . . . 422
Abhiram Ranade, 2013. Do not distribute 12
25.1.4 Simple examples of use . . . . . . . . . . . . . . . . . . . . . . . . . . 423
25.2 The restaurant simulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426
25.3 Resour es . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 427
25.3.1 A Resour e lass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 427
25.3.2 Simple example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 429
25.3.3 The o ee shop simulation . . . . . . . . . . . . . . . . . . . . . . . . 429
25.4 Single sour e shortest path . . . . . . . . . . . . . . . . . . . . . . . . . . . . 431
25.4.1 Dijkstra's algorithm as a simulation . . . . . . . . . . . . . . . . . . . 433
25.5 Con luding Remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 435
26 Simulation of an airport 438
26.0.1 Chapter outline . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 439
26.1 The simulation model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 439
26.1.1 Overall fun tioning . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440
26.1.2 Safe operation and half-runway-ex lusion . . . . . . . . . . . . . . . . 440
26.1.3 S heduling strategy . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441
26.1.4 Gate allo ation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441
26.1.5 Simulator input and output . . . . . . . . . . . . . . . . . . . . . . . 441
26.2 Implementation overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 442
26.2.1 Safe operation and half-runway-ex lusion . . . . . . . . . . . . . . . . 442
26.2.2 Gate representation and allo ation . . . . . . . . . . . . . . . . . . . 442
26.3 Main program and data stru ture . . . . . . . . . . . . . . . . . . . . . . . . 443
26.4 The taxiway lass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443
26.5 The ATC lass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 445
26.6 The plane lass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449
26.7 Deadlo ks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450
26.8 Con luding remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451
27 Non-linear simultaneous equations 454
27.1 Newton-Raphson method in many dimensions . . . . . . . . . . . . . . . . . 454
27.1.1 The general ase . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 456
27.1.2 Termination . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457
27.1.3 Initial guess . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457
27.2 How a ne kla e reposes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457
27.2.1 Formulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457
27.2.2 Initial guess . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 458
27.2.3 Experien e . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 459
27.3 Remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 459
27.4 Exer ises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 459
A Installing Simple pp 460
B Managing Heap Memory 461
B.1 Referen e Counting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 463
B.2 The template lass shared ptr . . . . . . . . . . . . . . . . . . . . . . . . . 463
B.2.1 Syntheti example . . . . . . . . . . . . . . . . . . . . . . . . . . . . 464
Abhiram Ranade, 2013. Do not distribute 13
B.2.2 General strategy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 465
B.2.3 Shared pointer in derivative nding . . . . . . . . . . . . . . . . . . . 465
B.2.4 Weak pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 468
B.2.5 Solution idea . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 468
B.3 Con luding remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 469
C Libraries 470
C.0.1 Linking built-in fun tions . . . . . . . . . . . . . . . . . . . . . . . . 470
D Reserved words in C++ 472
E Operators and operator overloading 473
E.1 Bitwise Logi al operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473
E.1.1 Or . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473
E.1.2 And . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 474
E.1.3 Ex lusive or . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 474
E.1.4 Complement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 474
E.1.5 Left shift . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 474
E.1.6 Right shift . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 475
E.2 Comma operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 475
E.3 Operator overloading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 476
F The stringstream lass 477
G The C++ Prepro essor 479
H Lambda expressions 480
H.1 General form . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 481
H.1.1 The type of a lambda expression . . . . . . . . . . . . . . . . . . . . 481
H.1.2 Variable apture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 481
H.1.3 Dangling referen es . . . . . . . . . . . . . . . . . . . . . . . . . . . . 482
H.1.4 Capturing this . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 482
Prefa e

This book presents an introdu tion to programming using the language C++. No prior
knowledge of programming is expe ted, however the book is oriented towards a reader who
has nished about 12 years of s hooling, preferably in the S ien e stream.
The book presents a fairly omprehensive introdu tion to the C++ language, in luding
some ex iting additions to it in the latest standard. However, the goal of the book is to
tea h programming, whi h is di erent from merely learning the di erent statements in any
programming language. Programming, like any skill, must be integrated with the other
knowledge and skills that the learner has. Also, programming is a liberating skill whi h an
hange your world view. Programming enables you to experiment/play with the math or
physi s that you have learned. You have been told that planets must move around the sun;
but if you know programming you an write a program to he k if this laim might be true.
In general, programming should en ourage you to make a model of the world around you
and experiment with it on a omputer. Obviously, this requires a ertain experien e and
knowledge about the world. It is our thesis that 12 years of s hooling in the S ien e stream
an indeed provide su h knowledge. In any ase, the book has been written not only to tea h
programming to our target readership, but also to hallenge and provoke them to using it in
ex iting ways.
This book does not emphasize any spe i programming methodology. Instead, we have
tried to present ideas in order of intelle tual simpli ity as well as simpli ity of programming
syntax. The general presentation style is: \Here is a problem whi h we would like to solve
but we annot using the programming primitives we have learned so far; so let us learn this
new primitive". Obje t oriented programming is learly important, but an attempt is made
to let it evolve as a programming need. We dis uss this more in Se tion 0.3.
This book is expe ted to be used along with a pa kage, simple pp, developed for use
in the book. Appendix A ontains instru tions for installing simple pp and the s ript that
an be used to ompile user programs that use simple pp. This pa kage ontains (a) a set
of graphi s lasses whi h an be used to draw and manipulate simple geometri shapes on
the s reen, and (b) some prepro essor ma ros whi h help in smoothing out the introdu tion
of C++ in the initial period. We feel that the use of simple pp an onsiderably help in
learning C++. This is dis ussed in greater detail below.
We on lude this prefa e by suggesting how this book an be tted into a urri ulum.

0.1 Graphi s
I hear and I forget. I see and I remember. I do and I understand.

14
Abhiram Ranade, 2013. Do not distribute 15
{Confu ius
Traditionally, introdu tory programming uses the domain of numbers or text to illustrate
programming problems and programming strategies. However, a large part of the human
experien e deals with pi tures and motion. This is espe ially true for our target reader.
Humans have evolved to have a good sense of geometry and geography, and are experts
at seeing patterns in pi tures and also planning motion. If this expertise an be brought
into a tion while learning programming, it an make for a more mature intera tion with the
omputer. It is for this reason that simple pp was primarily developed.
Our pa kage simple pp ontains a olle tion of graphi s lasses whi h allow simple geo-
metri al shapes to be drawn and manipulated on the s reen. Ea h shape on the s reen an
be ommanded to move or rotate or s ale as desired. Taking inspiration from the hildren's
programming language Logo, ea h shape also has a pen, whi h may be used to tra e a urve
as the shape moves. The graphi s lasses enable several omputational a tivities su h as
drawing interesting urves and patterns and performing animations together with omputa-
tions su h as ollision dete tion. These a tivities are hallenging and intuitive at the same
time.
The graphi s lasses are used right from the rst hapter. The introdu tory hapter
begins with a program to draw polygons. The program statements ommand a turtle 1

holding a pen to tra es the lines of the polygon. An immediate bene t is that this simple
exer ise makes the imperative aspe t of programming and notions su h as ontrol ow very
obvious. A more important realization, even from this very elementary session is the need to
re ognize patterns in the pi ture being drawn. A pattern in the pi ture often translates to
an appropriate programming pattern, say iteration or re ursion. Identifying and expressing
patterns is a fundamental a tivity in programming. These onsiderations an be brought to
the fore very easily.
As you read along, you will see that graphi s is useful for explaining many on epts, from
variable s oping and parameter passing to inheritan e based design. Graphi al fa ilities make
several traditional examples (e.g. tting lines to points, or simulations) very vivid. Finally,
graphi s is a lot of fun, a fa tor not to be overlooked. After all, edu ators worldwide are
on erned about dwindling student attention and how to attra t students to a ademi s.

0.2 First day/ rst month blues


C++, like many professional programming languages, is not easy to introdu e to novi es.
Many introdutory programming books begin with a simple program that prints the mes-
sage \hello world". On the fa e of it, this is a very natural beginning. However, even a
simple program su h as this appears ompli ated in C++ be ause it must be en ased in a
fun tion, main, having a return type int. The notion of a return type is learly inappropriate
to explain on the very rst day. Other on epts su h as namespa es are even more daunt-
ing. The only possibility is to tell the students, \dont worry about these, you must write
these mantras whose meaning you will understand later". This doesnt seem pedagogi ally
satisfa tory.
1 Represented by a triangle on the s reen, as in the language Logo.
Abhiram Ranade, 2013. Do not distribute 16
After the student has somehow negotiated through int main and namespa es, there is
typi ally a long preparatory period in whi h substantial basi material su h as data types
and ontrol stru tures has to be learnt, until any interesting program an be written. Psy-
hologi ally and logisti ally, this \slow" period is a problem. Psy hologi ally, a preparatory
period without too mu h intelle tual hallenge an be viewed by the student as boring, whi h
is a bad initial impression for the subje t. Se ond, in most ourse o erings, students tend
to have weekly le ture hours and weekly programming pra ti e hours. In the initial weeks,
students are fresh and rearing to go. It is disappointing to them if there is nothing ex iting
to be done, not to mention the waste of time.
To ounter these problems the following features have been in luded in simple pp.
Instead of the main program being spe i ed inside a fun tion main returning int, a
prepro essor ma ro main program is de ned (it expands to int main()). The main program
an be written as
main_program{
body
}
Further, on e the student loads in the simple pp pa kage using #in lude <simple pp>,
nothing additional needs to be loaded, nor using dire tives given. The simple pp pa kage
itself loads other header les su h as iostream and issues the using dire tives. These
\training wheels" are taken o when fun tions et . are explained (Chapter 9).
A se ond \language extension" is the in lusion of a \repeat" statement. This statement
has the form
repeat( ount){body}

and it auses the body to be exe uted as many times as the value of the expression ount.
This is also implemented using prepro essor ma ros and it expands into a for statement.
We believe that the repeat statement is very easy to learn, given a good ontext. Indeed,
it is introdu ed in Chapter 1, where instead of using a separate statement to draw ea h edge
of a polygon, a single line drawing statement inside a repeat statement suÆ es. In fa t the
turtle-based graphi al drawing examples are ompelling enough that students do not have
any diÆ ulty in understanding nested repeat statements either.
In the se ond and third hapters, there is a dis ussion of omputer hardware, data rep-
resentation and data types. These topi s are important, but are not amenable to good
programming exer ises. For this period, the repeat statement together with the notions in-
trodu ed in the rst hapter an be used very fruitfully to generate relevant and interesting
programming exer ises.
In addition, simple pp ontains some mis ellaneous fa ilities, a fun tion to generate
random numbers in a range, and lasses for managing event driven simulations. The ode
for all this is of ourse provided, and the student an look at the ode when he or she is
ready to do so.
Abhiram Ranade, 2013. Do not distribute 17
0.3 Obje t oriented programming
The dominant paradigm in modern programming pra ti e is learly the obje t oriented
paradigm. As a result, there have been approa hes to edu ation whi h attempt to introdu e
lasses and obje ts from \day 1". But even the proponents of these approa hes have noted
that lasses and obje ts are diÆ ult to tea h from the rst day for a number of reasons. For
example, for very simple programs, organizing programs into lasses might be very arti ial
and verbose. Expe ting a student to a tually develop lasses very early requires understand-
ing a fun tion abstra tion (for developing member fun tions/methods) even before ontrol
stru tures are understood. This an appear unmotivated and overwhelming.
Our dis ussion of obje t oriented programming an be onsidered to begin in Chapter 5:
reating a graphi al shape on the s reen requires reating an obje t of a graphi s lass.
However, in the initial hapters, it is only ne essary to use lasses, not build new lasses.
Thus shapes an be reated, and member fun tions invoked on them to move them around
et .
Classes are presented as an evolution of the stru t notion of the programming language
C. The major dis ussion of lasses in luding the modern motivations happens in Chapter 16,
however member fun tions are introdu ed in Se tion 15.5. Inheritan e is presented in Chap-
ter 23. Chapter 24 presents inheritan e based design. It ontains a detailed example in
whi h a program developed earlier, without inheritan e, is redeveloped, but this time using
inheritan e. This vividly shows how inheritan e an help in writing reusable, extensible
ode. A brief des ription of the design of simple pp graphi s system is also given, along
with an extension to handle omposite obje ts.

0.4 Fitting the book into a urri ulum


The book an be used for either a one semester ourse or a two semester sequen e.
For a one semester ourse, the re ommended syllabus is Chapters 1 through Chapter 16,
Chapter 19, Chapter 23. Many of these hapters ontain multiple examples of the same
on ept, all of these need not be \ overed" in lass. In addition, Chapter 20 should be
dis ussed, at least at a high level.
A two semester sequen e an over Chapters 1 through Chapter 16 in the rst semester,
going over them arefully and onsidering at length aspe ts su h as proving orre tness of
programs. The se ond semester ould over the remaining hapters. In a two semester
ourse, it would be appropriate to introdu e some of the modern ideas su h as referen e
ounting pointers (Appendix B).
Chapter 1

Introdu tion

A omputer is one of the most remarkable ma hines invented by man. Most other ma hines
have a very narrow purpose. A wat h shows time, a amera takes pi tures, a tru k arries
goods from one point to another, an ele tron mi ros ope shows magni ed views of very small
obje ts. Some of these ma hines are mu h larger than a omputer, and many mu h more
expensive, but a omputer is mu h, mu h more omplex and interesting in the kind of uses
it an be put to. Indeed, many of these ma hines, from a wat h to an ele tron mi ros ope
typi ally might ontain a omputer inside them, performing some of the most vital fun tions
of ea h ma hine. The goal of this book is to explain how a omputer an possibly be used
for so many purposes, and many more.
Viewed one way, a omputer is simply an ele tri al ir uit; a giant, omplex ele tri al
ir uit, but a ir uit nevertheless. In prin iple, it is possible to make omputers without the
use of ele tri ity { indeed there have been designs of omputers based on using me hani al
gears, or uidi s devi es. But all that is mostly of histori al importan e. For pra ti al
1

purposes, today, it is ne to regard a omputer as an ele tri al ir uit. Parts of this ir uit
are apable of re eiving data from the external world, remembering it so that it an be
reprodu ed later, pro essing it, and sending the results ba k to the external world. By data
we ould mean di erent things. For example, it ould mean some numbers you type from the
keyboard of a omputer. Or it ould mean ele tri al signals a omputer an re eive from a
sensor whi h senses temperature, pressure, light intensity and so on. The word pro ess might
mean something as simple as al ulating the average of the sequen e of numbers you type
from the keyboard. It ould also mean something mu h more omplex: e.g. determining
whether the signals re eived from a light sensor indi ate that there is some movement in
the vi inity of the sensor. Finally, by \send data to the external world" we might mean
something as simple as printing the al ulated average on the s reen of your omputer so
that you an read it. Or we ould mean a tivating a beeper onne ted to your omputer if
the movement dete ted is deemed suspi ious. Exa tly whi h parts of the ir uit are a tive
at what time is de ided by a program fed to the omputer.
It is the program whi h distinguishes a omputer from most other ma hines; by installing
di erent programs the same omputer an be made to behave in dramati ally di erent ways.
How to develop these programs is the subje t of this book. In this hapter, we will begin
1 Also it is appropriate to think of our own brain as a omputer made out of biologi al material, i.e.
neurons or neural ells.

18
Abhiram Ranade, 2013. Do not distribute 19
by seeing an example of a program. It turns out that we an understand, or even develop
(typi ally alled write) programs without knowing a lot about the spe i ir uits that the
omputer ontains. Learning to write programs is somewhat similar to how one might learn
to drive a ar; learly one an learn to drive without knowing how exa tly an automobile
engine works. Indeed, not only will you be able understand the program that we show you,
but you will immediately be able to write some simple programs.
There are many languages using whi h programs an be written. The language we will
use in this book is the C++ programming language, invented in the early 1980s by Bjarne
Stroustrup. For the initial part of the book, we will not use the bare C++ language, but
instead augment it with a pa kage alled simple pp whi h we have developed. How to
install this pa kage is explained in Appendix A. We developed this pa kage so that C++
appears more friendly and more fun to people who are starting to learn C++. To use the
driving metaphor again, it ould be said that C++ is like a omplex ra ing ar. When you
are learning to drive, it is better to start with a simpler vehi le, in whi h there aren't too
many onfusing ontrols. Also, standard C++ does not by default ontain the ability to
draw pi tures. The pa kage simple pp does ontain this feature. We thus expe t that by
using the simple pp pa kage it will be easier and more fun to learn the language. But in
a few hapters (by Se tion 11.6), you will outgrow simple pp and be able to use standard
C++ (like \the pros"), unless of ourse you are using the graphi s features.

1.1 A simple program


Our rst example program is given below.
#in lude <simple pp>
main_program{
turtleSim();

forward(100);
left(90);
forward(100);
left(90);
forward(100);
left(90);
forward(100);

wait(5);
}

If you exe ute this program on your omputer, it will rst open a window. Then a small
triangle whi h we all a turtle will appear in the window. Then the turtle will move and
2

draw lines as it moves. The turtle will draw a square and then stop. After that, the window
will vanish, and the program will end. Shortly we will des ribe how to exe ute the program.
2 Our turtle is meant to mimi the turtle in the Logo programming language.
Abhiram Ranade, 2013. Do not distribute 20
First we will tell you why the program does all that it does, and this will help you modify
the program to make it do something else if you wish.
The rst line #in lude <simple pp> de lares that the program makes use of some fa il-
ities alled simple pp in addition to what is provided by the C++ programming language.
The next line, main programf, says that what follows is the main program. The main
3

program itself is ontained in the bra es f g following the text main program.
The line following that, turtleSim() auses a window with a triangle at its enter to
be opened on the s reen. The triangle represents our turtle, and the s reen the ground on
whi h it an move. Initially, the turtle points in the East dire tion. The turtle is equipped
with a pen, whi h an either be raised or lowered to tou h the ground. If the pen is lowered,
then it draws on the ground as the turtle moves. Initially, the pen of the turtle is lowered,
and it is ready to draw.
The next line forward(100) auses the turtle to move forward by the amount given
in the parentheses, (). The amount is to be given in pixels. As you might perhaps know,
your s reen is really an array of small dots, ea h of whi h an be of any olour. Typi al
s reens have an array of about 1000  1000 dots. Ea h dot is alled a pixel. So the ommand
forward(100) auses the turtle to go forward in the urrent dire tion it is pointing by about
a tenth of the s reen size. Sin e the pen was down, this auses a line to be drawn.
The ommand left(90) auses the turtle to turn left by 90 degrees. Other numbers
ould also be spe i ed instead of 90. After this, the next ommand is forward(100), whi h
auses the turtle to move forward by 100 pixels. Sin e the turtle is fa ing north this time, the
line is drawn northward. This ompletes the se ond side of the square. The next left(90)
ommand auses the turtle to turn again. The following forward(100) draws the third side.
Then the turtle turns on e more be ause of the third left(90) ommand, and the fourth
forward(100) nally draws the fourth side and ompletes the square.
After this the line wait(5) auses the program to do nothing for 5 se onds. This is the
time you have to admire the work of the turtle! After exe uting this line, the program halts.
Perhaps you are puzzled by the () following the ommand turtleSim. The explanation
is simple. A ommand in C++ will typi ally require additional information to do its work,
e.g. for the forward ommand, you need to spe ify a number denoting how far to move. It
just so happens that turtleSim an do its work without additional information. Hen e we
need to simply write (). Later you will see that there an be ommands whi h will need
more than one pie es of information, in this ase we simply put the pie es inside () separated
by ommas.
1.1.1 Exe uting the program
To exe ute this program, we must rst have it in a le on your omputer. It is ustomary to
use the suÆx . pp for les ontaining C++ programs. So let us suppose you have typed the
program into a le alled square. pp { you an also get the le from the CD or the book
webpage.
Next, we must ompile the le, i.e. translate it into a form whi h the omputer under-
stands more dire tly and an exe ute. The translation is done by the ommand s++ whi h
got installed when you installed the pa kage simple pp. The ommand s++ merely invokes
3 Yes, there an be non-main programs too, as you will see later.
Abhiram Ranade, 2013. Do not distribute 21
the GNU C++ ompiler, whi h must be present on your omputer (See Se tion A). In a
UNIX shell you an ompile a le by typing s++ followed by the name of the le. In this ase
you would type s++ square. pp. As a result of this another le is produ ed, whi h ontains
the program in a form that is ready to exe ute. On UNIX, this le is typi ally alled a.out.
This le an be exe uted by typing its name to the shell
% a.out
You may be required to type ./a.out be ause of some quirks of UNIX. Or you may be able
to exe ute by double li king its i on. When the program is thus exe uted, you should see
a window ome up, with the turtle whi h then draws the square.

1.2 Remarks
A C++ program is similar in many ways to a paragraph written in English. A paragraph
onsists of senten es separated by full stops; a C++ program ontains ommands whi h must
be separated by semi- olons. Note that while most human beings will tolerate writing in
whi h a full-stop is missed, a omputer is very fastidious, ea h ommand must be followed by
a semi- olon. Note however, that the omputer is more forgiving about the use of spa es and
line breaks. It is a eptable to put in spa es and linebreaks almost anywhere so long as words
or numbers are not split or joined. Thus it is perfe tly legal (though not re ommended!) to
write
turtleSim();forward(100) ;
left (90
);
if you wish. This exibility is meant to enable you to write su h that the program is easy to
understand. Indeed, we have put empty lines in the program so as to help ourselves while
reading it. Thus the ommands whi h a tually draw the square are separated from those
that open and lose the windows. Another important idea is to indent, i.e. put leading spa es
before lines that are part of main program. This is again done to make it visually apparent
what is a part of the main program and what is not. As you might observe, indentation is
also used in normal writing in English.
1.2.1 Exe ution order
There is another important similarity between programs and text written in a natural lan-
guage su h as English. A paragraph is expe ted to be read from left to right, top to bottom.
So is a program. By default a omputer exe utes the ommands left to right, top to bottom.
But just as you have dire tives in magazines or newspaper su h as \Please ontinue from
page 13, olumn 4", the order in whi h the ommands of a program are exe uted an be
hanged. We see an example next.
Abhiram Ranade, 2013. Do not distribute 22
1.3 Repeating a blo k of ommands
At this point you should be able to write a program to draw any regular polygon, say a
de agon. You need to know how mu h to turn at ea h step. The amount by whi h you turn
equals the exterior angle of the polygon. But we know from Eu lidean Geometry that the
exterior angles of a polygon add up to 360 degrees. A de agon has 10 exterior angles, and
hen e after drawing ea h side you must turn by 360=10 = 36 degree. So to draw a de agon
of side length 100, we repeat the forward(100) and right(36) ommands 10 times. This
works, but you may get bored writing down the same ommand several times. Indeed, you
dont need to do that. Here is what you would write instead.
#in lude <simple pp>
main_program{
turtleSim();
repeat(10){
forward(100);
left(36);
}
wait(5);
}

This program, when exe uted, will draw a de agon. The new statement in this is the
repeat. Its general form is

repeat( ount){
statements
}

In this, ount ould be any number. The statements ould be any sequen e of statements
whi h would be exe uted as many times as the expression ount, in the given order. The
statements are said to onstitute the body of the repeat statement. Ea h exe ution of the
body is said to be an iteration. Only after the body of the loop is exe uted as many times
as the value of ount, do we exe ute the statement following the repeat statement.
So in this ase the sequen e forward(100); left(36); is exe uted 10 times, drawing
all 10 edges of the de agon. Only after that do we get to the statement wait(5);
1.3.1 Drawing any regular polygon
Our next program when exe uted, asks the user to type in how many sides the polygon
should have, and then draws the required polygon.
#in lude <simple pp>
main_program{
int nsides;
out << "Type in the number of sides: ";
in >> nsides;
Abhiram Ranade, 2013. Do not distribute 23

turtleSim();

repeat(nsides){
forward(50);
left(360.0/nsides);
}
wait(5);
}
This program has a number of new ideas. The rst statement in the main program
is int nsides; whi h does several things. The rst word int is short for \integer", and
it asks that a region be reserved in memory in whi h integer values will be stored during
exe ution. Se ond, it also gives a name to this region: nsides. Finally it de lares that from
now on, whenever the programmer uses the name nsides it should be onsidered to refer
to this region. It is ustomary to say that nsides is a variable, whose value is stored in the
asso iated region of memory. This statement is said to de ne the variable nsides. As many
variables as you want an be de ned, either by giving separate de nition statements, or by
writing out the names with ommas in between. For example, int nsides, length; would
de ne two variables, the rst alled nsides, the se ond length. We will learn more about
names and variables in Chapter 3.
The next new statement is relatively simple. out is a name that refers to the omputer
s reen. It is ustomary to pronoun e the in out (and in in the next statement) as \see".
The sequen e of hara ters << denotes the operation of writing something on the s reen.
What gets written is to be spe i ed after the <<. So the statement in our program will
display the message
Type in the number of sides:
on the s reen. Of ourse, you may put in a di erent message in your program, and that will
get displayed.
In the statement after that, in >> nsides;, the name in refers to the keyboard. It
asks the omputer to wait until the user types in something from the keyboard, and whatever
is typed is pla ed into the (region asso iated with) the variable nsides. The user must type
in an integer value followed by typing the return key. The value typed in gets pla ed in
nsides.
After the in >> nsides; statement is exe uted, the omputer exe utes the repeat
statement. Exe uting a repeat statement is nothing but exe uting its body as many times
as spe i ed. In this ase, the omputer is asked to exe ute the body nsides times. So
if the user had typed in 15 in response to the message asking for the number of sides to
be typed, then the variable nsides would have got the value 15, and the loop body would
be exe uted 15 times. The loop body onsists of the two statements forward(100) and
left(360.0/nsides). Noti e that instead of dire tly giving the number of degrees to turn,
we have given an expression. This is allowed! The omputer will evaluate the expression,
and use that value. Thus in this ase the omputer will divide 360.0 by the value of the
variable nsides, and the result is the turning angle. Thus, if nsides is 15, the turning angle
will be 24. So it should be lear that in this ase a 15 sided polygon would be drawn.
Abhiram Ranade, 2013. Do not distribute 24
1.3.2 Repeat within a repeat
What do you think the program below does?
#in lude <simple pp>
main_program{
int nsides;

turtleSim();

repeat(10){
out << "Type in the number of sides: ";
in >> nsides;
repeat(nsides){
forward(50);
left(360.0/nsides);
}
}
wait(5);
}
The key new idea in this program is the appearan e of a repeat statement inside another
repeat statement. How does a omputer exe ute this? Its rule is simple: to exe ute a
repeat statement, it just exe utes the body as many times as spe i ed. In ea h iteration
of the outer repeat statement there will one exe ution of the inner repeat statement. But
one exe ution of the inner repeat ould have several iterations. Thus, in this ase a single
iteration of the outer repeat will ause the user to be asked for the number of sides, after the
user types in the number, the required number of edges will be drawn by the inner repeat
statement. After that, the next iteration of the outer repeat would begin, for a total of 10
iterations. Thus a total of 10 polygons would be drawn, one on top of another.

1.4 Some useful turtle ommands


The following ommands an also be used.
penUp(): This auses the pen to be raised. So after exe uting this ommand, the turtle
will move but no line will be drawn until the pen is lowered. There is nothing inside the ()
be ause no number is needed to be spe i ed, as was the ase with forward, e.g. forward(10).
penDown(): This auses the pen to be lowered. So after exe uting this ommand, a line
will be drawn whenever the turtle moves, until the pen is raised again.
Thus if you write repeat(10)fforward(10); penUp(); forward(5); penDown();g a
dashed line will be drawn.

1.5 Numeri al fun tions


The ommands you have seen so far for ontrolling the turtle will enable you to draw several
interesting gures. However you will noti e that it is umbersome to draw some simple
Abhiram Ranade, 2013. Do not distribute 25
gures. For example, if you wish to draw an iso eles right angled triangle, then you will
need to take square roots { and we havent said how to do that. Say you want to draw
a simple right angled triangle with side lengths in the proportion 3:4:5. To spe ify the
angles would require a trigonometri al ulation. We now provide ommands for these and
some ommon operations that you might need. You may wonder, how does a omputer
al ulate the value of the sine of an angle, or the square root of a number? The answers to
these questions will ome later. For now you an just use the following ommands without
worrying about how the al ulation a tually happens.
Let us start with square roots. If you want to nd the square root of a number x, then the
ommand for that is sqrt. You simply write sqrt(x) in your program and during exe ution,
the square root of x will be al ulated, and will be used in pla e of the ommand. So for
example, here is how you an draw an iso eles right angled triangle.
forward(100);
left(90);
forward(100);
left(135);
forward(100*sqrt(2));
The ommands for omputing trigonometri ratios are sine, osine and tangent. Ea h
of these take a single argument: the angle in degrees. So for example, writing tangent(45)
will be as good as writing 1.
The ommands for inverse trigonometri ratios are ar sine, ar osine and ar tan.
These will take a single number as an argument and will return an angle (in degrees). For
example, ar osine(0.5) will be 60 as expe ted. These ommands return the angle in the
range -90 to +90. An important additional ommand is ar tan2. This needs two arguments,
y and x respe tively. Writing ar tan2(y,x) will return the inverse tangent of y/x in the full
range, -180 to +180. This an be done by looking at the signs of y and x, information whi h
would be lost if the argument had simply been y/x. Thus ar tan2(1,-1) would be 135,
while ar tan2(-1,1) would be -45, and ar tan(-1/1)=ar tan(1/-1)=ar tan(-1) would
also be -45.
Now to do a triangle with side lengths 75, 100, 125 you may simply exe ute the following.
forward(75);
left(90);
forward(100);
left(ar tan2(75,-100));
forward(124);
As you might guess, we an put expressions into arguments of ommands, and put the
ommands themselves into other expressions and so on.
Some other useful ommands that are also provided:
1. exp, log, log10 : These return respe tively for argument x the value of ex (where e
is Euler's number, the base of the natural logarithm), the natural logarithm and the
logarithm to base 10.
2. pow : This takes 2 arguments, pow(x,y) returns xy .
Abhiram Ranade, 2013. Do not distribute 26
3. sin, os, tan respe tively return the sine, osine, and tangent of an angle, but it
must be spe i ed in radians.
4. asin, a os, atan2 respe tively return the ar sine, ar osine and ar tangent, in radi-
ans. The ommand atan2 takes 2 arguments like the ommand ar tangent2 dis ussed
above.
C++ also has ommands sin, os, tan whi h return the trigonometri ratios given the
angle in radians. And for inverse trigonometri ratios we have the ommands asin, a os,
atan, atan2 whi h return the angle in radians.
The name PI an be used in your programs to denote , the ratio of the ir umferen e
of a ir le to its diameter.

1.6 Comments
The primary fun tion of a program is to get exe uted. Clearly, it should exe ute orre tly
and do whatever it is expe ted to do.
However, a program should be written so that it is easy to understand, when programmers
read it. The reason is simple. One programmer may write a program, whi h another
programmer may need to modify. In su h ases the se ond programmer must be able to
understand why the program was written in the manner it was written. This pro ess an
be aided if the original programmer writes additional notes to explain the tri ky ideas in
the program. For this purpose, C++ allows you to insert omments in your program. A
omment is text that is not meant to be exe uted, but is meant solely for humans who might
read the program.
A omment an be written in two ways. At any point on a line, you may pla e two slash
hara ters, //, and then the text following the // to the end of the line be omes a omment.
Alternatively, anything following the /* hara ters be omes a omment, and this omment
an span over several lines, ending only with the appearan e of the hara ters */.
It is ustomary to put omments at the beginning mentioning the author of the program
and stating what the program does. Subsequently, wherever something non-obvious is being
done in the program, it is onsidered polite to explain using a omment.
Here is our polygon drawing program written the way it should be written.
#in lude <simple pp>
/* Program to draw a regular polygon with as many sides as the user wants.
Author: Abhiram Ranade
Date: 18 Feb 2013.
*/
main_program{
int nsides;
out << "Type in the number of sides: ";
in >> nsides;

turtleSim();
Abhiram Ranade, 2013. Do not distribute 27
repeat(nsides){
forward(50); // Ea h side will have length 50 pixels.
left(360.0/nsides); // Be ause sum(exterior angles of a polygon) = 360.
}
wait(5);
}

1.7 Computation without graphi s


Although we began this introdu tion with a pi ture drawing program, every program you
write need not ontain any drawing. Here is a program that does not draw anything, but
merely reads a number from the keyboard, and prints out its ube.
main_program{
int n;
out <<"Type the number you want ubed: ";
in >> n;
out << n*n*n << endl;
}
The al ulation of n is similar to what you have seen earlier. Indeed, the general rule is that
3

whatever mathemati al operations you want performed an be expressed by writing them


out as you do normally. We dis uss the exa t rules later, in Se tion 3.2.

1.8 Con luding Remarks


Although it may not seem like it, in this hapter you have already learned a lot.
First, you have some idea of what a omputer program is and how it exe utes: starting
at the top and moving down one statement at a time going towards the bottom. If there are
repeat statements, the program exe utes the body of the loop several times; the program
is said to loop through the body for the required number of iterations.
You have learned the notion of a variable, i.e. a region of memory into whi h you an
store a value, whi h an later be used while performing omputations.
You have also learned several ommands using whi h you an draw, do al ulations (e.g.
take square root). Later on we will see how to ourselves build new ommands.
Finally, a very important point on erns observing the patterns in whatever you are doing.
When we draw a polygon, we repeat the same a tion several times. This is a pattern that
we an mirror in our program by using the repeat statement. By using a repeat statement
we an keep our program ompa t; indeed we may be drawing a polygon with 100 sides, but
our program only has a few statements. You will see other ways of apturing patterns in
your programs later. In general this is a very important idea.
At this point you should also see why the notation used to write programs is alled a
language. A spoken language is very exible and general. It has a grammati al stru ture, e.g.
there is a subje t, verb, and obje t; or there an be lauses, whi h an themselves ontain
subje ts, verbs, obje ts and other lauses. And so long as the stru ture is respe ted, you
Abhiram Ranade, 2013. Do not distribute 28

Figure 1.1: Can you draw this?


an have many, many, indeed an in nite number of senten es. Similarly, omputer programs
have a stru ture, e.g. a repeat statement must be followed by a ount and a body; but
inside the body there an be other statements in luding a repeat statement. Indeed our
treatment of the C++ programming language will be somewhat similar to how you might
be taught Marathi or Fren h. Just as language learning is more fun if you read interesting
literature, we will introdu e the C++ language as we try to solve more and more interesting
omputational problems. Hope you will nd this enjoyable.
1.8.1 Graphi s
The main a tivity that omputers engage in is of ourse al ulating with numbers. However,
there are many reasons we began this introdu tion pi ture drawing, and why pi ture drawing
will be an important parallel theme that will run through the book.
Programs are not a mere list of al ulations you want done; as you will see it is important
to understand the patterns in the al ulation and represent them in your program. Both
these a tivities: understanding patterns and representing them in your program, are needed
also when you draw pi tures. In general, both the a tivities are quite diÆ ult. But in ase
of pi tures, the patterns are often very obvious. Thus, you an fo us your attention on the
task of representing them in the program. We will see many examples of this later.
Also note that drawing interesting pi tures requires mu h areful al ulation, using ge-
ometry and trigonometry that you have learned earlier. Thus, pi ture drawing will provide
4

another domain in whi h you an pra ti e your omputational skills.


4 Do not worry if you have forgotten some of this; we will refresh your memory when needed.
Abhiram Ranade, 2013. Do not distribute 29
Also remember the adage \A pi ture is worth a thousand words.". Indeed, it is very
useful if you an show the result of your omputation through a pi ture. Also, in a lot of
appli ations it is useful if you an provide input to the program by drawing a pi ture or
li king on the s reen, rather than by typing in numbers. In general, and espe ially for
omputation on mobile phones and tablet omputers, the areas of data visualization and
graphi al user interfa es are be oming very important, and our pi ture drawing exer ises
will give you a taste of these areas.
And nally, drawing pi tures is fun.
1.8.2 A note regarding the exer ises
Programming is not a spe tator sport. To really understand programming, you must write
many, many programs yourself. That is when you will dis over whether you have truly
understood what is said in the book. To this end, we have provided many exer ises at the
end of ea h hapter, whi h you should assidously solve.
Another important suggestion: while reading many times you may nd yourself asking,
\What if we write this program di erently". While the author will not be present to answer
your questions, there is an easy way to nd out { write it di erently and run it on your
omputer! This is the best way to learn.

1.9 Exer ises


In all the problems related to drawing, you are expe ted to identify the patterns/repetitions
in what is asked, and use repeat statements to write a on ise program as possible. You
should also avoid ex essive movement of the turtle and tra ing over what has already been
drawn.
1. Modify the program given in the text so that it asks for the side length of the polygon
to be drawn in addition to asking for the number of sides.
2. Draw a sequen e of 10 squares, one to the left of another.
3. Draw a hessboard, i.e. a square of side length say 80 divided into 64 squares ea h of
sidelength 10.
4. If you draw a polygon with a large number of sides, say 100, then it will look essentially
like a ir le. In fa t this is how ir les are drawn: as a many sided polygon. Use this
idea to draw the numeral 8 { two ir les pla ed tangentially one above the other.
5. A pentagram is a ve pointed star, drawn without lifting the pen. Spe i ally, let
A,B,C,D,E be 5 equidistant points on a ir le, then this is the gure A{C{E{B{D{A.
Draw this.
6. Draw a seven pointed star in the same spirit as above. Note however that there are
more than one possible stars. An easy way to gure out the turning angle: how many
times does the turtle turn around itself as it draws?
Abhiram Ranade, 2013. Do not distribute 30
7. We wrote \360.0" in our program rather than just \360". There is a reason for this
whi h we will dis uss later. But you ould have some fun guring it out. Rewrite
the program using just \360" and see what happens. A more dire t way is to put
in statements out << 360/11; out << 360.0/11; and see what is printed on the
s reen. This is an important idea: if you are urious about \what would happen if I
wrote ... instead of ...?" { you should simply try it out!
8. Read in the lengths of the sides of a triangle and draw the triangle. You will need to
know and use trigonometry for solving this.
9. When you hold a set of ards in your hand, you usually arrange them fanned out. Say
you start with ards sta ked one on top of the other. Then you rotate the ith ard
from the top by an amount proportional to i (say 10i degrees to the left) around the
bottom left orner. Now, we an see the top ard ompletely, but the other ards are
seen only partially. In parti ular, only a triangular portion of ea h ard is seen, with
the top left orner being at the apex of ea h triangle. This is the gure that you are
to draw. (a) Draw it assuming the ards are transparent. (b) Draw it assuming the
ards are opaque. For this some trigonometri al ulation will be ne essary. In both
ases, use repeat statements to keep your program small as possible.
10. Draw a pattern onsisting of 7 ir les of equal radius: one in the enter and 6 around
it, ea h outer ir le tou hing the entral ir le and two others. Try to write a program
whi h minimizes turtle movement. Your program statements should be hosen to
exploit the symmetry in the pattern.
11. Draw the pi ture shown in Figure 1.1. As you an see, the pi ture has 36 repetitions of
a basi pattern. Your program should be able to take a number n as input, and draw
a pi tures having n repetitions. Make sure that the lines and the ar s in the pattern
onne t smoothly.
Chapter 2

A bird's eye view

Chapter 1 provided a hands-on introdu tion to omputers and programming. This hapter
is also introdu tory. In the rst part we will give a high level overview of the pro ess of
problem solving using omputers. In the se ond part we will give a high level overview of
omputer hardware. This ba kground will be useful when we dig into details of programming
from the next hapter.
The rst step in solving any problem on a omputer is to formulate it as a problem on
numbers. On e this is done, you try to gure out what operations you need to perform and
in what order, to solve the numeri al problem. In this step, you an pretend, if you wish,
that you are solving the problem manually using pen il and paper. A sequen e of operations
that is guaranteed to solve the problem, des ribed pre isely, is alled an algorithm. On e
you have an algorithm, it must be expressed in a language su h as C++, when e it be omes
a program whi h an exe ute on a omputer. We dis uss all this in Se tion 2.1.
In the se ond part of the hapter we onsider questions su h as how omputers perform
al ulations and how numbers are stored and pro essed in them. In Se tion 2.2 we dis uss the
basi features of the ir uits used in omputers. In Se tion 2.3 we dis uss in detail di erent
formats used for representing numbers inside omputers. In Se tion 2.4 we dis uss the
overall organization of a omputer. Then we onsider how individual parts work. We dis uss
the on ept of a program stored in memory, and other on epts relevant to programming
su h as the on ept of an address. We on lude by dis ussing what it means to ompile a
C++ program. The hapter ontains a lot of detail whi h is given only for the purpose of
illustrating the on epts. It is not to be taken literally, or remembered.

2.1 Problem solving using omputers


As dis ussed above, the rst step in solving a problem using a omputer is to express it
as a problem on numbers. This is easy for several real life problems whi h are represented
numeri ally to begin with. Commer e requires us to keep tra k of pri es and pro ts and
apital and salaries, and learly this requires numbers and substantial omputation on those
numbers. Numbers are also obviously needed to represent quantities su h as temperature,
length, mass, for e, voltage, on entration of hemi als. So it would seem that problems
involving su h quantities will be naturally formulated using numbers. However, it is not lear
that this holds for all real life entities. For example, an we express pi tures or language
31
Abhiram Ranade, 2013. Do not distribute 32
0 0 0 1 1 1 0 0 0 0
0 0 1 0 0 0 1 1 0 0
0 1 0 0 0 0 0 0 1 0
1 0 0 0 0 0 0 0 1 0
1 0 1 0 0 0 1 0 0 1
1 0 0 0 0 0 0 0 0 1
1 0 0 1 1 1 0 0 1 0
0 1 0 0 0 0 0 0 1 0
0 0 1 0 0 0 1 1 0 0
0 0 0 1 1 1 0 0 0 0

(a) (b) (c)

Figure 2.1: A pi ture, its representation, and re onstru tion

using numbers? We dis uss these questions next.


Here is how a pi ture might be represented using numbers. Consider a bla k and white
pi ture to begin with. We rst divide the pi ture into small squares by putting down a
ne grid over it, as in Figure 2.1(a). Then for ea h small square we determine whether it
is more white or more bla k. If the square is more white we assign it the number 0, if it
is more bla k, we assign it the number 1. So if we have divided the pi ture into m  n
small squares (pixels), m along the height and n along the width, we have a sequen e of mn
numbers, ea h either 1 or 0 that represents the pi ture. Figure 2.1 shows the numbers we
have assigned to ea h square. Given the mn number representation, we an re onstru t the
pi ture as follows: wherever a 0 appears, we leave the orresponding square white, wherever
a 1 appears, we make the orresponding square bla k. The re onstru tion, using the numbers
in Figure 2.1(b) is shown in Figure 2.1( ). As you an see, the re onstru ted pi ture is not
identi al to the original pi ture, but reasonably similar. By hoosing a ner grid, we would
have been able to get a better approximation of the original pi ture. It turns out that pixels
of size about 0.1 mm are good enough, i.e. the re onstru ted pi ture is hard to distinguish
from the original be ause our eye annot individually see su h ne squares. Pro essing a
pi ture means doing omputations involving these numbers. For example, hanging every
zero to a one and vi e versa, will hange the pi ture from \positive" to \negative"! Similar
ideas are used when we wish to display pi tures on a omputer monitor, as will be dis ussed
in Se tion 2.7.2.
It should be noted that the idea of putting down a grid over the obje t of interest is very
powerful. Suppose we wish to represent the worldwide weather. So we divide the surfa e of
the globe into small regions. For ea h region we onsider the urrent state i.e. parameters
relevant to the weather su h as the ambient temperature, pressure, humidity. Of ourse,
all points in a region will not have identi al temperature but we nevertheless an hoose
an approximate representative temperature, if the region is reasonably small. And similarly
pressure or humidity. This olle tion of state information for all regions is a representation of
the urrent worldwide weather. Given the urrent state of a region and the laws of physi s
we an al ulate what the next state will be only by looking at the state of the nearby
regions. This is a very gross simpli ation of how the weather is predi ted, but, it is orre t
in essen e.1

This is not to say that all physi al phenomenon related to the weather are well understood. In fa t,
1
many simple things are not understood, e.g. how pre isely do rain drops form. However, we understand
enough (through the hard work of several s ientists) to make predi tions with some on den e. All this is
Abhiram Ranade, 2013. Do not distribute 33
Text is represented using numbers as follows. Essentially, we devi e a suitable ode.
The most ommon ode is the so alled ASCII (Ameri an Standard Code for Information
Inter hange) ode. In this, the letter \a" is represented as the number 97, \b" as 98 and so
on. Standard symbols and the spa e hara ter also have a ode assigned to them. So the
word \ omputer" is represented by the sequen e of numbers 99,111,109,112,117,116,101,114.
On e we an express text, we have a foothold for expressing senten es, paragraphs, and all
of language! A paragraph is also represented as a sequen e, probably a very long sequen e.
Finding whether a given word o urs in a given paragraph is simply he king whether one
sequen e of numbers is a subsequen e of another sequen e of numbers! Note that the ASCII
ode is used to represent all text written using the Roman alphabet, in luding the C++
programs you will write. The Uni ode Consortium provides odes to represent text in other
alphabets, su h as Devanagari.
We will see more real life obje ts (and mathemati al obje ts too, su h as sets, fun tions)
and how to represent them in the rest of the book.
2.1.1 Algorithms and programs
After a problem has been represented numeri ally, the next step is to solve it. For this, we
need to de ide what operations to perform and in what order. Su h a sequen e of operations,
des ribed pre isely, is said to onstitute an algorithm.
To determine the algorithm, it is ne if you pretend you are doing the omputation on
pen il and paper. An algorithm an have steps of the form \Multiply these two numbers,
then add the result to the ratio of these other two numbers" and so on. You an also have
steps su h as, \If this number is zero then do this". Or also something like \Keep on doing
this until ...". The key requirement is that there should be no ambiguity about what is to
be done at any point in the algorithm. On e you have determined the algorithm, i.e. the
pre ise sequen e of a tions, you an think about expressing it in C++. That will give us the
program. Of ourse, for doing the last step you need to know C++. This you will learn in
the rest of the book.
We should point out that while the term algorithm may be new to you, you have a tually
learned many algorithms starting from primary s hool. For example, you know how to
determine whether a given positive integer n is prime. Probably, you will do this as follows:
starting from the integer 2, try out all integers till n 1 and he k if they divide n (without
leaving a remainder). If you nd an integer that divides n, then de lare n to be omposite.
If you don't nd any su h integer, then de lare n to be a prime. This is indeed an algorithm
to determine whether a number n is prime! We will soon see (Se tion 6.7.2) how it an be
turned into a C++ program. You have learned algorithms even earlier. For example, you
learned how to add up numbers, or subtra t or multiply or divide them. These pro edures
are also algorithms! You probably learned these pro edures by example, or through pi tures,
su h as the one in Figure 2.2, in whi h you are rst asked to make a multipli ation table for
the given divisor (in this ase 23), and then on the right you a tually perform the division.
Even these basi algorithms will be of value. Indeed, they will ome in handy when you
want to perform arithmeti with very large numbers, as in Exer ise 21 of Chapter 13.
of ourse well outside the s ope of this book.
Abhiram Ranade, 2013. Do not distribute 34
23 1406
46 23 32358
69 23
92
115 93
138 92
161 158
184 138
207 20

Figure 2.2: Primary s hool division algorithm

Of ourse, algorithm design is diÆ ult, if you are not familiar with the domain of the
problem you want to solve. For example, if you want to predi t the weather, you had
better know di erential equations and physi s. So we will not onsider su h problems in this
book. We will onsider problems from more familiar domains, e.g. high s hool and junior
ollege math and s ien e, simple ommer e, and of ourse ommon sense! Or if we onsider
unfamiliar domains, we will rst present the relevant ba kground.

2.2 Basi prin iples of digital ir uits


Here is the key fa t: the ir uits in a omputer are designed su h that for pra ti al purposes,
we an pretend that numbers ow through the wires in the ir uit, or get stored in the
devi es in the ir uit. Su h ir uits are alled digital ir uits. We only dis uss digital ir uits
in this hapter. In digital ir uits, at any time instant, we an think of ea h individual wire
as arrying a single number, or to be more pre ise, either the number 0 or the number
1. Likewise, there are devi es, that are apable of performing a storage fun tion (most
ommonly apa itors), and ea h su h individual devi e an also store the number 0 or the
number 1 at any time.
We brie y explain how this illusion is reated. But you an ignore this paragraph if you
wish, it is not needed for understanding the rest of the book. As you may know, urrent ows
through the wires in an ele tri al ir uit (just as water ows through pipes), and wires are
asso iated with voltages (ele tri al equivalent of water pressure). The idea for representing
numbers in ir uits is simple: if a wire is at a ertain designated high voltage (say higher
than 1 volt) then we will say that the number 1 is being arried on it. If the wire is at a
ertain designated low voltage (say smaller than 0.2 volts), then we will say that the wire is
arrying the number 0. Note further that the ir uits are designed so that the wires never
arry voltages in the range 0.2 volts to 1 volt, and so there is never any ambiguity. Thus we
an pretend that wires in the ir uit are arrying around numbers. Further note that if you
store ele tri al harge on a apa itor, the harge does not dissipate qui kly; in this sense the
apa itor remembers that harge. To make the apa itor remember a 0, we simply drain o
harge from it. This will happens if we onne t the apa itor to our designated low voltage.
If on the other hand, we onne t our apa itor to a high voltage, a large amount of harge
Abhiram Ranade, 2013. Do not distribute 35
gets stored on it; this represents the number 1. For the rest of the book, we will not worry
about harges and voltages. Instead we will only talk about apa itors and wires holding
and arrying the numbers 0 or 1.
Of ourse, we will want to store or ommuni ate numbers besides 0 and 1. We will see
how to do this in Se tion 2.3. On e we have numbers represented, it is possible to design
ir uits whi h an perform arithmeti on them. This is onsidered in Se tion 2.6.

2.3 Number representation formats


The term bit is used to denote a number whi h is either 0 or 1, so we will say that ea h
wire in a omputer an arry a single bit, or ea h apa itor an store a single bit. If we
want to represent other numbers, we an do so by asso iating with them a sequen e of bits.
As an example, say we de ide to asso iate the sequen e of bits 11001 with the number 25.
Then whenever we want to store 25, we will need to use 5 apa itors, and in them store the
respe tive bits of the sequen e, i.e. 1, 1, 0, 0, 1. Likewise, if we want to send the number 25
from one devi e to another, we must have 5 wires, and on those we must respe tively send
1, 1, 0, 0, 1. The question then is, what bit sequen e should we asso iate with ea h number?
The simplest idea is as follows: we represent the number using the sequen e of bits given
by its binary representation. So as an example, suppose we wish to represent the number
25. It has binary representation 11001. Thus it would be represented by the sequen e of
bits 11001, as dis ussed above. This idea is ne if we only wish to represent non-negative
integers. It is ommonly used, as we dis uss in Se tion 2.3.1.
But our program may deal with integers whi h an be either positive or negative e.g. tem-
perature rounded to the nearest degree. Thus we need a more omplex s heme to represent
su h numbers. This is dis ussed in Se tion 2.3.2.
More generally we may have to represent quantities su h as mass, for e, and velo ities,
whi h in general will be real numbers, and may be either positive or negative. S hemes for
representing real numbers are dis ussed in Se tion 2.3.3.
There is one more issue to onsider. In the example above, we said that the number 25
ould be represented by a sequen e of 5 bits. On most omputers, the standard representation
s hemes require you to hoose the length of the sequen e to be one of 8, 16, 32, or 64 bits.
This is be ause restri ting the size of the bit sequen e to these values makes it easy to design
the ir uitry in the omputer. Note that it is ustomary to use the terms byte, half-word,
word, and double-word to respe tively mean 8, 16, 32 and 64 bits.
2.3.1 Unsigned integer representation
Suppose we know that a ertain quantity we deal with in our program will always be a non-
negative integer, e.g. a telephone number. In that ase, as dis ussed above, we an represent
it using the sequen e of bits given by its binary representation. As mentioned above, the
length of the representation must be hosen to be one of 8, 16, 32, 64. Thus if the number
we wish to represent has a shorter binary representation than the length we hose, then we
simply make the more signi ant bits 0, e.g. if we wish to represent 25 using 32 bits, the
representation will be the bit string
Abhiram Ranade, 2013. Do not distribute 36

00000000000000000000000000011001
Note that if we de ide to use an n bit long binary representation, the maximum value that
an be represented is 2n 1 (sequen e of n 1s). Thus we must be sure that the number we wish
to represent is not larger. As an example, sin e we know that telephone numbers (in India)
are at most 8 digits long, and sin e the largest possible 8 digit number 99999999 < 2 1, 32

we an use n = 32 to represent telephone numbers.


2.3.2 Signed integers
An integer an be negative or positive. So this throws a hallenge: how do we represent
negative numbers?
The simplest representation is the so alled sign-magnitude representation. In this, if we
have n bits to be used for representing the number, one of these is designated as a sign bit.
We will set this bit to 0 if the number is positive, and to 1 if the number is negative. The
remaining n 1 bits will be used for representing the absolute value of the number. We
might use the bit in the most signi ant position as the sign bit, so the representation for
-25 using the 32 apa itors would be the bit string:
10000000000000000000000000011001
Noti e that sin e we have de ided to use n 1 bits to represent the magnitude, the magnitude
an be at most 2n 1 (all n 1 bits must be 1s). Sin e the numbers an be positive or
1

negative, using n bits total we an represent numbers between 2n +1 and 2n 1, both


1 1

in lusive.
A more ommonly used representation is the so alled 2's omplement representation. The
n bit 2s omplement representation is de ned as follows. In this the integer x is represented
by the n bit binary representation of the number x if 0  x  2n 1, and by the n bit
1

binary representation of the number 2n x if 2n  x < 0. Numbers outside this range


1

annot be represented. 2

Here is how -25 would be represented in 32 bit 2's omplement representation. Sin e -25
is negative, we have to represent it by the binary number 2 25 = 4294967296 25 =
32

4294967271. Then we take its binary representation, whi h is: 3

11111111111111111111111111100111
Thus if you want to store -25 or send it on some wires, the above bit pattern will have to be
stored or sent.
2.3.3 Floating point representations
Mu h omputing needs to be done with real numbers. For example, velo ities of parti les,
voltages, temperatures and so on in general need not take only integral values. Real numbers
This only means that there is no standard, built-in me hanism for representing numbers outside the
2
range. However, you will be able to design your own me hanisms if you wish, as you are asked to in
Exer ise 21 of Chapter 13.
3 You may nd it onvenient to rst onvert 232 and 25 to binary, and then subtra t.
Abhiram Ranade, 2013. Do not distribute 37
are represented using the so- alled oating point representations. Usually, oating point
representations use bit strings of length 32 or 64.
In the s ienti world real numbers are typi ally written using the so alled s ienti
notation, in the form: f  10q , where the signi and f typi ally has a magnitude between
1 and 10, and the exponent q is a positive or negative integer. For example the mass of an
ele tron is 9:109382  10 kilograms, or Avogadro's number is 6:022  10 .
31 23

On a omputer, real numbers are represented using a binary analogue of the s ienti
notation. So to represent Avogadro's number, we rst express it in binary. This is not hard
4

to do: it is
1:11111110001010101111111  2 1001110

Note that this is approximate, and orre t only to 3 de imal digits. But then, 6:022  10 23

was only orre t to 3 digits anyway. The exponent 1001110 in de imal is 78. Thus the
number when written out fully will have 78 bits. We ould use 78 bits to represent the
number, however, it seems unne essary. Usually we will not need that mu h pre ision in our
al ulations. A better alternative, is to represent ea h number in two parts: one part being
the signi and, and the other being the exponent.
For example, we ould use 8 bits to represent the exponent, and 24 bits to represent the
signi and, so that the number is neatly tted into a single 32 bit word! This turns out
to be essentially the method of hoi e on modern omputers. You might ask why use an
8-24 split of the 32 bits and why not 10-22? The answer to this is: experien e. For many
al ulations it appears that an exponent of 8 bits is adequate, while 24 bits of pre ision in
the signi and is needed. There are s hemes that use a 64 bit double word as well and the
split here is 11-53, again based on experien e.
Note that the signi and as well as the exponent an be both positive or negative. One
simple way to deal with this is to use a sign-magnitude representation, i.e. dedi ate one bit
from ea h eld for the sign. Note that we don't need to expli itly store the de imal point (or
we should say, binary point!) { it is always after the rst bit of the signi and. Assuming
that the exponent is stored in the more signi ant part or the word, Avogadro's number
would then be represented as:
0; 1001110; 0; 11111111000101010111111
Two points to be noted: (a) we have put ommas after the sign bit of the exponent, the
exponent itself, and the sign bit of the signi and, only so it is easy to read. There are no
ommas in memory. (b) Only the most signi ant 23 bits of the signi and are taken. This
requires throwing out less signi ant bits (what happened in this example), but you might
even have to pad the signi and with 0s if it happens to be smaller than 23 bits.
As another example, onsider representing 12:3125. This is -1100.0101 in binary, i.e.
1:1000101  2 . Noting that our number is negative and our exponent is positive, the
3

representation would be
0; 0000011; 1; 110001010000000000000000
Again the ommas are added only for ease of reading.
In the s ienti notation, the position of the de imal point within the signi and depends upon the value
4
of the exponent. Hen e the name oating point.
Abhiram Ranade, 2013. Do not distribute 38
The exa t format in whi h real numbers are represented on modern omputer hardware
and in C++ is the IEEE Floating Point Standard. It is mu h more ompli ated, but has
more features, some of whi h we will dis uss later.

2.4 Organization of a omputer


We an think of a omputer as onsisting of the following main parts. An a tual omputer
will ontain more parts, but all are not of interest to us in this high level sket h.
1. Main memory. In this we store the numbers on whi h we are performing our al ula-
tions. As we will see later, the memory will also hold the program.
2. Arithmeti unit. This is apable of performing arithmeti . We supply to it the
operands, tell it what operation we want performed, and it does so. We an then
extra t the result and store it ba k in memory.
3. Input-output devi es. There an be many, but we onsider the keyboard, the display,
whi h is often referred to as the monitor or the s reen, and the disk.
4. Control Unit. This ontrols the other units, as the name implies.
5. Network. This is useful for moving data between the parts.
It is ustomary to use the term Central Pro essing Unit to denote the ontrol unit together
with the arithmeti unit.
You may think of ea h part as onsisting of a box with ir uitry inside. Ea h part has
ports (sets of wires) on whi h data an ome out from the part or go into the part. It is
possible to take the data out of one part and send it to another part through the network.
How exa tly the data ows is determined by the ontrol unit. This organization is sket hed
in Figure 2.3. The ontrol unit has onne tions to every other unit, we have not shown them
in the pi ture to avoid lutter.

2.5 Main memory


The memory of a modern omputer may ontain a huge number of basi memory elements,
say 2 . These are usually apa itors as dis ussed earlier. Ea h basi memory element is
35

apable of storing 1 bit. The number of bits that an be stored is de ned to be the apa ity,
or the size, of the memory. More ommonly, the memory size is measured in bytes, where a
byte is simply 8 bits. Thus a memory with 2 apa itors has size 2 bits or 2 bytes, or 4
35 35 32

Gigabytes.
2.5.1 Addresses
Ea h byte (group of 8 elementary memory devi es, say apa itors) in the memory is asso i-
ated with a unique label, or address. If a memory has N bytes, then the addresses an start
at 0 and end at N 1 (Figure 2.3). Note that while in day to day life we would have used
Abhiram Ranade, 2013. Do not distribute 39

Output
Control Arithmetic unit
Input 1 input 2

Byte 0
Byte 1 Keyboard
Byte 2
. Address Port
.
.
. Memory Network Monitor
.
.
.
. Data Port
.
Disk
Byte N−1

Read control Write control

Control Unit

Figure 2.3: Computer Organization (sket h)

labels from 1 to N , on omputers it is more ustomary to start with 0. The address of a


byte is useful for identifying it from among all the bytes in the memory. Note that addresses
are unsigned integers. Thus they an be represented using their binary representation.
The phrase \byte x" is ommonly used to mean the byte whose address is x. The phrase
\word x" is also used, this simply means the word starting at byte x, i.e. the set of bytes
x; x + 1; x + 2; x + 3. Similarly for half-words and double words.
The phrase \lo ation x" is also used; usually it means the word starting at address x.
However, it may mean byte x or double word x based on the ontext.
2.5.2 Ports and operations
A memory ommuni ates with the rest of the world using 2 sets of wires or ports. The
rst is the address port, and the se ond the data port. There are also two additional wires
onne ting to the memory: we will all the rst the read ontrol port and the se ond the
write ontrol port. Using these we an a ess the ontents of the memory as follows. In
what follows we use the phrase \pla e a quantity" to mean \pla e the representation of that
quantity".
1. Storing data into byte x: For this it is ne essary to pla e the address x on the address
port, and the data that you want stored, say the number y, on the data port. Then
you pla e the number 1 on the write ontrol port. This signals the memory to store
the data on the data port into the byte whose address is present on the address port.
Abhiram Ranade, 2013. Do not distribute 40
Thus the number y will be stored in byte x. Byte x will ontinue to hold the number
y until another write operation is performed on byte x.
2. Reading data from byte x: For this, you pla e the address x, on the address port. Then
you pla e a 1 on the read ontrol port. The 1 on the read ontrol port signals the
memory to sense the data stored in byte x of the memory and pla e it on the data
port. On e data appears on the data port, it an be moved from there to where it is
needed.
What we des ribed above is a byte-oriented memory. More ommon are word-oriented mem-
ories. In these, when we supply an address, the word starting at the given address is sent
ba k or written to. In byte-oriented memories, the data port will onsist of 8 wires, be ause
8 bits need to be ommuni ated. In word-oriented memories, the data port will likewise have
to have 32 wires. Similarly for half-words and double word oriented memories.
How many wires do we need in the address port? Let us take our 2 byte memory as an
32

example. In this memory, the addresses range from 0 to 2 1. Thus the largest address
32

onsists of 32 onse utive 1s. Hen e the address port will have to have 32 wires, in order
that we may spe ify any possible address. In general, if the memory has N bytes, then we
will need to have log N wires in the address port.
2

2.6 The arithmeti unit


The arithmeti unit has ir uits using whi h it is possible to perform basi arithmeti opera-
tions, i.e. addition, subtra tion, multipli ation, division, for numbers in all formats des ribed
earlier, unsigned and signed integers, and oating. It re eives the operands through two ports
named Input1 and Input2 and the result of the operation is pla ed on the port named Out-
put, see Figure 2.3. What operation is to be performed depends upon the value supplied
on the Control port. The arithmeti unit an also onvert numbers from one representation
to another, e.g. given a number represented as an integer on one of the inputs, its repre-
sentation in the oating format (exponent and signi and) an be produ ed on the output
port.
You may think that the arithmeti unit must onsist of many very ompli ated ir uits.
That is indeed true. However, for the purpose of programming, we don't need to know how
the ir uits are to be designed, it is suÆ ient to know what they an do.

2.7 Input-Output Devi es


The input-output devi es are onsidered to be peripherals, and the rest of the omputer the
\main omputer".
2.7.1 Keyboard
The simplest input devi e is a keyboard. A ode number is assigned to ea h key on the
keyboard. When a key is pressed, the orresponding ode number is sent to the main
Abhiram Ranade, 2013. Do not distribute 41
omputer. The ontrol unit de ides what is to be done with the re eived ode number; for
example it might just get stored in the memory.
2.7.2 Display
A omputer terminal s reen or display is a fairly omplex devi e. You probably know that a
display is made up of pixels whi h are arranged in a grid, say 1024 rows and 1024 olumns.
Ea h pixel an be made to show the olour you desire. By showing appropriate olours, you
an display pi tures, or letters, or the turtle from Chapter 1. The display hardware de ides
what olour to show by onsulting a small amount of memory asso iated with ea h pixel.
The amount of memory depends on the sophisti ation of the display. For a simple bla k and
white display, it is enough to spe ify whether the pixel is to appear white or bla k. So a
single bit of memory is enough. You may also have displays whi h an show di erent levels
of brightness: k bits of memory will be able to store numbers between 0 and 2k 1 and hen e
that many levels of brightness, or gray levels. In olour displays we need to simultaneously
store the red, green, blue omponents at ea h pixel, and so presumably even more bits are
needed. Indeed high quality olour displays might use as many as 24 bits of memory for ea h
pixel. To display an image, all we need to do is to store appropriate values in the memory
asso iated with ea h pixel in the s reen. If we have 24 bits of memory per pixel, then be ause
there are 1024  1024 = 2 pixels, we will need a memory with addresses between 0 and
20

2 1, ea h ell of the memory onsisting of 24 bits. A reasonable orresponden e is used


20

to relate the pixels and addresses in memory: the olour information for the pixel (i; j ) i.e.
the pixel in row i and olumn j (with 0  i; j < 1024) is stored in address 1024i + j of the
memory. When the ir uitry of the s reen needs to display the olour at pixel (i; j ) it pi ks
up the olour information from address 1024i + j of the memory. If you wish to hange the
image, it suÆ es to hanges the data in the memory. So in some ways, the display an be
treated very mu h like another memory. The main omputer an a ess the display memory,
but it should not be onfused with the main memory of the omputer.
2.7.3 Disks
Devi es su h as disks an also be thought of as storing data at ertain addresses, however,
the addresses no longer refer to spe i apa itors in the ir uitry, but spe i lo ations on
the magneti surfa e. The magneti surfa e an be magnetized in di erent dire tions: the
dire tion indi ates whether a 0 or a 1 is stored there.
Opti al ompa t disks also fun tion in a similar manner. The surfa e of an opti al
ompa t disk has elevations and dips whi h an be dete ted by shining a laser on them.
Whether a ertain region of the disk stores a 0 or it stores a 1 is determined by the pattern
of elevations and dips in that region.
2.7.4 Remarks
There is a lot of innovation and ingenuity in designing peripheral devi es. This is of ourse
outside the s ope of this book.
Abhiram Ranade, 2013. Do not distribute 42
However, the fundamental ideas should be noted: (a) ommuni ation between the main
omputer and the peripheral devi e happens by sending numbers, (2) information is stored
as bits, by designating some physi al property to determine whether a 0 or a 1 is stored (3)
if several bits are stored, there will be a notion of address using whi h we an refer to some
sele ted bit or group of bits.

2.8 The Control Unit


As the name implies, the Control Unit ontrols the other parts of a omputer. The ontrol
unit ontains omplex ir uitry. But it is possible to understand its fun tion at a high level.
When you want to solve a problem, you would like the omputer to perform a ertain
sequen e of operations, depending upon the algorithm you have de ided for the problem.
To take a simple example, suppose you want to ompute the ube of a number. Then you
would like the number to be read from the keyboard and put into some lo ation in memory,
say the word at address 100. After that you would like the arithmeti unit to multiply the
number at the lo ation by itself, two times and then put the result at some other lo ation,
say lo ation 104. Finally, you would like the number at lo ation 104 to be displayed on the
s reen. If you want to solve some other problem, then a di erent sequen e of operations
would have to be performed.
The ontrol unit an get the other parts of the omputer to perform whatever a tion you
may desire, in luding the a tions noted above. However, you must somehow tell the ontrol
unit what you want. How do you do this?
Here is the outline of the answer: you store the sequen e of a tions you want performed
in the memory of the omputer, and then ask the ontrol unit to perform those a tions, in
the order you have stored them. Many details need to be explained: (a) how do we store
a tion sequen es in memory, (b) an we design ir uits using whi h the ontrol unit an
\understand" what is stored in memory and perform the required a tion. The answer to
part (b) is Yes, the ontrol unit indeed ontains the required ir uits, but any explanation
of these ir uits is outside the s ope of this book.
A high level answer to part (a) is as follows. It follows the basi idea that on a omputer,
everything is represented using numbers, in luding a tions that you want the omputer
to perform! The omputer designer provides you with a numeri al oding system alled
ma hine language using whi h you an tell the ontrol unit what you want. As an example,
the omputer designer may de ide that (a) the sequen e of numbers of the form 53; x (for any
x) means the ontrol unit should perform the a tions needed to read a real number from the
keyboard and put it into the memory lo ation x, (b) sequen es of the form 57; x; y; z mean
the ontrol unit should perform the a tions needed to multiply the real numbers in lo ations
x; y and store the result in lo ation z , ( ) sequen es of the form 63; x mean the ontrol unit
should perform the a tions needed to display the real number in lo ation x on the s reen,
and (d) the sequen e onsisting of just the number 99 means the ontrol unit should shut
down the omputer. Ea h su h sequen e of numbers is alled a ma hine instru tion, and a
sequen e of ma hine instru tions is alled a ma hine language program. Thus, the sequen e
of numbers 53, 100, 57, 100, 100, 104, 57, 100, 104, 104, 63, 104, 99. would represent a
ma hine language program onsisting of the instru tions:
Abhiram Ranade, 2013. Do not distribute 43
 53, 100. This would read in a real number from the keyboard.
 57, 100, 100, 104. This would multiply the number in memory lo ations 100 with itself
and put the result in lo ation 104. Thus the square of the number will get pla ed in
lo ation 104. Note that after this instru tion exe utes we will have the original number
and its square in lo ations 100 and 104 respe tively.
 57, 100, 104, 104. This would multiply the number in memory lo ations 100 and
104 and put the result in lo ation 104. Thus the number and its square would get
multiplied, and the result, the ube, would get pla ed in lo ation 104.
 63,104. This would print out the ube on the s reen.
 99. The program would stop.
Me hanisms would be provided using whi h you ould store this sequen e of instru tions in
memory, say from lo ation 0, and then ask the ontrol unit to start exe uting the program
starting at lo ation 0.
We made up the format of the instru tions to reate the example program given above.
No real omputer has the given instru tions. Note further that there is no reason why we
hose the pattern 57; x; y; z to denote an instru tion that multiplies numbers. The designer
ould have hosen another number instead of 57. The point is that the designer would have
to reate some set of instru tions, and the omputation you want would have to be expressed
using those instru tions. Many, many di erent instru tions will be needed, to express all the
di erent basi fun tions a omputer an perform. Here is an example. Suppose you wish to
have integer numbers in lo ations x; y and wish to pla e their produ t in lo ation z, then the
instru tion 57; x; y; z would not work be ause it would interpret the bit pattern in lo ations
x; y as a real number (Se tion 2.3.3), ompute the produ t and store the resulting real
number in lo ation z. So the designer would have to provide another type of instru tion, say
58; x; y; z for multiplying integers, and say also 59; x; y; z for multiplying unsigned integers.
Here is another example. We spe i ed above that the ontrol unit exe utes the rst
instru tion in our program, then the next, and then the next and so on. But what if we
want to exe ute some instru tions several times, say be ause we have a repeat statement?
To do this onveniently, the designer will usually provide a onvenient ma hine instru tion.
Thus our designer may designate that some other sequen e, say 73; x means that ontrol unit
should start exe uting instru tions from lo ation x. So onsider the program 53, 100, 57,
100, 100, 104, 57, 100, 104, 104, 63, 104, 73, 0, 99. Suppose the program is stored starting
at lo ation 0. Now after exe uting 73, 0, the ontrol would not exe ute the next instru tion
in memory, 99, as it usually does. But instead 73,0 asks it to exe ute the next instru tion
starting at lo ation 0. Thus, it would ause the instru tion 53, 100 to be exe uted again
and so on. Thus another number would be read, and its ube would be displayed. And this
would happen again, and again, ad in nitum. More ommonly, you will want a sequen e
of instru tions to be repeated some nite number of times, the ma hine language will also
ontain instru tions for that purpose. We will omit the details of this.
Abhiram Ranade, 2013. Do not distribute 44
2.8.1 Control Flow
Suppose the ontrol unit is urrently exe uting the instru tion taken from address x of the
memory. Then it is ustomary to say that the ontrol (unit) is at that instru tion, or at
the address x. The sequen es of memory lo ations from whi h the ontrol unit pi ks up the
instru tion and exe utes them is said to onstitute the path of ontrol ow. Alternatively,
we might say that ontrol ows through that sequen e of instru tions or memory lo ations.
Note that similar phrases are also used in onne tion with C++ programs: we will say that
the ontrol is at a given statement of the program and so on.

2.9 High level programming languages


When the earliest omputers were built, they ould be used only by writing ma hine language
programs. Indeed, you had to de ide where in memory you would store your data, look up the
omputer manual and determine what instru tion would perform the a tions you wanted,
and then write out the sequen e of numbers that would onstitute the ma hine language
program. Then the ma hine language program would have to be loaded into the omputer
memory, and then you ould exe ute the program. As you might guess, this whole pro ess
is very tiring and error prone.
Fortunately, today, programs an be written in the style seen in Chapter 1, and what will
be dis ussed in the rest of the book. We do not think about what instru tions to use, nor
the address in memory where to store the number of sides of the polygon we wish to draw.
Instead, we use familiar mathemati al expressions to denote operations we want performed.
We give names to regions of memory and store data in them by referring to those names.
The omputer, of ourse, really only \understands" instru tion odes and memory addresses,
and does not understand mathemati al notation or the names we give to parts of memory.
So how does our ni e looking program a tually exe ute on a omputer?
Clearly, the ni e looking programs we write must rst be translated into ma hine language
instru tions whi h the omputer does understand. This is done by a program alled a
ompiler, whi h fortunately has been written by someone already! The program s++ that
you used in the last hapter is a C++ ompiler, whi h takes a C++ program (e.g. the
one from Se tion 1.7) and generates the le (e.g. a.out) whi h ontains a ma hine language
program like what we dis ussed in Se tion 2.8. When you type
a.out
from the ommand line or li k on the program i on, the ontent of the le a.out gets loaded
into the memory, and then what is loaded starts getting exe uted.

2.10 Con luding Remarks


The rst important point made in this hapter is that for solving any problem, you rst
need to express it as a problem on numbers. In some ases this is easy, whereas in some
other ases, we had to produ e some kind of a oding s heme. We also de ned the notion of
algorithms, and gave examples of algorithms that are learned in primary s hool.
Abhiram Ranade, 2013. Do not distribute 45
The se ond important point was that numbers an be pro essed using appropriately
designed ir uits. We an think of numbers as physi al ommodities whi h take up spa e
as they are stored and when they are moved. You an even (metaphori ally!) onsider that
number have mass, be ause energy is needed to move them around in a omputer! We then
saw, at a high level, how parts of a omputer fun tion. We also saw, how su h ir uits an
be ontrolled using programs, and that these programs are sequen es of instru tions, ea h
of whi h is also represented using numbers! Finally, we dis ussed notions su h as an address
and the orresponden e between ma hine language and C++.
We on lude with the remark that our des ription of omputer hardware in this hapter
is very simple-minded, and that real hardware is mu h more elaborate.

2.11 Exer ises


All the exer ises below are meant to be only paper and pen il exer ise.
1. How would you represent a position in a hess game? Or you an answer this question
for any board game you are familiar with.
2. Make sure you are able to onvert numbers from de imal to binary and vi e versa. You
may not be familiar with onverting fra tions. For this simply note that a 1 in the
ith position after the (binary) point, has pla e value 2 . Thus 0.1 in binary is just
1

half, 0.01 is just one fourth. So now you should be able to de ide whether the rst bit
after the point should be one or not, by omparing the fra tional part to half. The
remaining bits an be de ided by extending the idea. You will not need to onvert
fra tions in this book, however, it will be useful to be able to onvert intgers routinely.
So pra ti e with di erent examples.
3. How many di erent numbers are represented in the sign magnitude representation on
n = 3 bits? Make a table showing what bit pattern represents whi h number.
4. How many di erent numbers are represented in the n bit 2's omplement representa-
tion? Make a table showing what bit pattern represents whi h number.
5. Suppose you want to draw a \+" symbol at the enter of a 1024  1024 display.
Suppose the display will show a pixel white if you store a 1 at the orresponding
memory lo ation. Suppose the \+" is 100 pixels tall and wide, and 2 pixels thi k. In
whi h s reen memory lo ations would you store 1s?
Chapter 3

Numbers

In this hapter we will see C++ statements for pro essing numbers. By \pro essing numbers"
we mean a tions su h as reading numbers from the keyboard, storing them in memory,
performing arithmeti or other operations on them, and writing them onto the s reen. We
have already seen some examples in Chapter 1. In this hapter, we will build up on that and
state everything more formally and more generally.
As mentioned in Chapter 2, textual data is also represented numeri ally on a omputer:
ea h hara ter is represented by its numeri al ASCII ode. Text pro essing turns out to be
a minor variation of numeri pro essing. Logi al data is also represented numeri ally. We
onsider these topi s brie y, they are onsidered at length in Se tion 14.1 and Se tion 6.7
respe tively.
Using the repeat statement and what we learn in this hapter we will be able to write
some interesting programs. We see some of these at the end.

3.1 Variables and data types


A region of memory allo ated for holding a single pie e of data (for now a single number),
is alled a variable. C++ allows you to reate a variable, i.e. allo ate the memory, and give
it a name. The name is to be used to refer to the variable in the rest of the program. A
variable an be reated by writing the following in your program.
data-type variable-name;

In this, data-type must be a data-type sele ted from the rst olumn of Table 3.1, and
variable-name a name hosen as per Se tion 3.1.1. The term data-type is used to denote
the type of values expe ted to be stored in the variable ( olumn 4), and the size of memory
allo ated ( olumn 3).
You have already seen some examples, e.g. in Se tion 1.3.1 we wrote:
int nsides;

We said then that this would reate a variable apable of storing integers. From Table 3.1 you
now also know that typi ally the variable will use 4 bytes of memory, and will store positive
and negative numbers. As dis ussed in Se tion 2.3.2 su h numbers are typi ally represented
46
Abhiram Ranade, 2013. Do not distribute 47

Data type Possible values # Bytes Use


(Indi ative) Allo ated for
(Indi ative) storing
signed har -128 to 127 1 Chara ters or
unsigned har 0 to 255 small integers.
short int -32768 to 32767 2 Medium size
unsigned short int 0 to 65535 integers.
int -2147483648 to 2147483647 4 Standard size
unsigned int 0 to 4294967295 integers.
long int -2147483648 to 2147483647 4 Storing longer
unsigned long int 0 to 4294967295 integers.
long long int 9223372036854775808 to 8 Even longer
9223372036854775807
unsigned long long int 0 to 18446744073709551615 integers.
bool false (0) or true (1) 1 Logi al values.
float Positive or negative. About 7 4 Real numbers.
digits of pre ision. Magnitude
in the range 1:17549  10 to
38

3:4028  1038

double Positive or negative. About 15 8 High pre ision


digits of pre ision. Magnitude and high range
in the range 2:22507  10 308
real numbers.
to 1:7977  10 308

long double Positive or negative. About 18 12 High pre i-


digits of pre ision. Magnitude sion and very
in the range 3:3621  10 to
4932
high range real
1:18973  104932
numbers.
Table 3.1: Fundamental data types of C++
Abhiram Ranade, 2013. Do not distribute 48
in the two's omplement representation, and if so the numbers in the range -2147483648 to
2147483647 an be stored.
C++ provides the types signed har, short int, long int, and long long int
for storing (positive or negative) integers. Variables of these respe tive types will use amount
of memory as given in Table 3.1 and will be able to store values in orrespondingly larger
or smaller range. In all su h ases, very likely the two's omplement representation of Se -
tion 2.3.2 is used.
If you know that you will only store non-negative integers in a ertain variable, you may
hoose one of the unsigned types. For example, you may write:
unsigned int telephoneNumber;
This will reate a variable alled telephoneNumber, using 4 bytes, and the values will be
stored using the binary representation, as dis ussed in Se tion 2.3.1. The types unsigned
har, unsigned short, unsigned long and unsigned long long are also used for stor-
ing non-negative integers. These will respe tively use di erent amount of memory and allow
orrespondingly smaller or larger ranges.
The following will reate a variable alled temperature for storing real numbers.
double temperature;
The reated variable will be 8 bytes long. It will typi ally use the IEEE Floating point
standard as dis ussed in Se tion 2.3.3. The type name double is short for \double pre ision",
in omparison to the type float whi h uses 4 bytes and is onsidered \single pre ision".
The rst 9 types in Table 3.1 are said to be integral types, and the last 3, floating
types.
It should be noted that the size shown for ea h data-type is only indi ative. The C++
language standard only requires that the sizes of har, short, int, long, long long to
be in non-de reasing order. Likewise, the sizes of float, double, long double are also
expe ted to be non-de reasing. The exa t sizes are may vary from one ompiler to another
but an be determined as dis ussed in Se tion 3.1.6.
The har types are most ommonly used for storing text, as we will see later. In su h
uses it is ustomary to omit the quali ers signed or unsigned and write:
har firstLetterOfName;
This will reate a 1 byte variable, of type either unsigned har or signed har. One of
these types will be hosen by the ompiler. Note that if you are using har to store text,
the exa t hoi e does not matter be ause the ASCII ode is uses only the range 0 to 127
whi h is present in either the signed or the unsigned version. If you use the har type to
store integers (that happen to lie in a small range) then it is best to spe ify whether you
want the signed or the unsigned type.
The type bool is primarily used to store logi al values, as will be seen in Se tion 6.7.
The phrase value of a variable is used to refer to the value stored in the variable. So the
stored telephone number (after it is stored, and we will say how to do this) will be the value
of the variable telephone number.
We nally note that you an de ne several variables in a single statement if they have
the same type, by writing:
data-type variable-name1, variable-name2, ... variable-namek;
Abhiram Ranade, 2013. Do not distribute 49
3.1.1 Identi ers
The te hni al term for a name in C++ is identi er. Identi ers an be used for naming
variables, but also other entities as we will see later.
An identi er an onsist of letters, digits and the unders ore hara ter \ ". Identi ers
annot start with a digit, hen e you annot have an identi er su h as 3rd ousin. It is
also not onsidered good pra ti e to use identi ers starting with an unders ore for naming
ordinary variables. Finally, some words are reserved by C++ for its own use, and these
annot be used as variable names. For example, int is a reserved word; it is not allowed to
be used as a variable name be ause it will be onfusing. The omplete list of reserved words
is given in Appendix D.
It is ustomary to name a variable to indi ate the intended purpose of the variable. For
example, if we want to store a velo ity in a variable, then we should give the name velo ity
to the variable.
An important point is that ase is important in names; so mathmarks is onsidered to
be a di erent name from MathMarks. Noti e that the latter is easier to read. This way of
forming names, in whi h several words are strung together, and in whi h the rst letter of
ea h word is apitalized, is said to be utilizing amel ase, or CamelCase. As you might
guess, the apital letters resemble the humps on the ba k of a amel. There are two kinds
of CamelCase: UpperCamelCase in whi h the rst letters of all the words are apitalized,
and lowerCamelCase, in whi h the rst letters of all but the rst word are apitalized. For
ordinary variables, it is more ustomary to use lowerCamelCase; thus it is suggested that
you use mathMarks rather than MathMarks.
If a variable is important in your program, you should give it a des riptive name, whi h
expresses its use. It is usually best to use omplete words, unabbreviated. Thus if you have a
variable whi h ontains the temperature, it is better to give it the name temperature rather
than t, or temp or tmprtre. Sometimes the des ription that you want to asso iate with a
variable name is very long. Or there is a lari ation that the reader should be be aware of.
In su h ases, it is good to add a omment explaining what you want immediately following
the de nition, e.g.
double temperature; // in degrees entigrade.

3.1.2 Literals and variable initialization


It is possible to optionally in lude an initial value along with the de nition. So we may
write:
int p=10239, q;
This statement de nes 2 variables, of whi h the rst one, p, is initialized to 10239. No initial
value is spe i ed for q, whi h means that some unknown value will be present in it. The
number \10239" as it appears in the ode above is said to onstitute an integer literal, i.e. it
is to be interpreted literally as given. Any integer number with or without a sign onstitutes
an integer literal. The words false and true are literals whi h stand for the values 0 and
1. So for bool variables, it is re ommended that you write initializations using these, e.g.
bool penIsDown = true;
Abhiram Ranade, 2013. Do not distribute 50
rather than writing bool penIsDown = 1; whi h would mean the same thing but would be
less suggestive. For onvenien e in dealing with har data, any hara ter en losed in a pair
of single quotes is an integer literal that represents the ASCII value of the en losed hara ter.
Thus you may write
har letter_a = 'a';
This would store the ode, 97, for the letter 'a' in the variable letter a. You ould also
have written har letter a = 97; but writing 'a' is preferred, be ause it is easier to
understand. In general, we may write a hara ter between a pair of single quotes, and that
would denote the ASCII value of the hara ter. Chara ters su h as the newline (produ ed
when you press the \enter" key), or the tab, an be denoted by spe ial notation, respe tively
as 'nn' and 'nt'. Note that literals su h as 'nn' and 'a' really represent an integer value. So
we an in fa t write
int q = 'a';

This would ause 97 to be stored in the int variable q.


To initialize oating variables, we need a way to spe ify real number literals. We an
spe ify real number literals either by writing them out as de imal fra tions, or using an
analogue of \s ienti notation". We simply write an E or e between the signi and and the
exponent, without leaving any spa es. Thus we would write Avogadro's number , 6:022  1

10 , as 6.022E23. The signi and as well as the exponent ould be spe i ed with a minus
23

sign, if needed, of ourse. For example the mass of an ele tron, 9:10938188  10 kg, would 31

be written as 9.10938188E-31. Thus we may write:


float w, y=1.5, avogadro = 6.022E23, eMass = 9.10938188E-31;
This statement de nes 4 variables, the se ond, third and fourth are respe tively initialized
to 1.5, 6:022  10 and 9:10938188  10 . The variable w is not initialized.
23 31

3.1.3 The onst keyword


Sometimes we wish to de ne identi ers whose value we do not wish to hange. For example,
we might be needing Avogadro's number in our program, and it will likely be onvenient to
refer to it using the name Avogadro rather than typing the value everytime. In C++ you
an use the keyword onst before the type to indi ate su h named onstants. Thus you
might write
onst float Avogardro = 6.022E23;

On e a name is de lared onst, you annot hange it later. The ompiler will omplain if
do attempt to hange it.
1 The number of mole ules in a mole of any substan e, e.g. number of arbon atoms in 12 gm of arbon.
Abhiram Ranade, 2013. Do not distribute 51
3.1.4 Reading data into a variable
To read a value into a variable pqr we write
in >> pqr;
Simply put: when this statement is exe uted, the omputer will wait for us to type a value
onsistent with the type of pqr. That value will then be pla ed in pqr.
The exa t exe ution pro ess for the statement is a bit ompli ated. First, the statement
ignores any whitespa e hara ters that you may type before you type in the value onsistent
with the type of pqr. The term whitespa e is used to olle tively refer to several hara ters
in luding the spa e hara ter (' '), the tab hara ter ('nt'), and the newline hara ter ('nn').
In addition, the verti al tab ('nv'), the formfeed hara ter ('nf') and the arriage return ('nr')
are also onsidered whitespa e. These three hara ters are now only of histori al interest.
The rst non whitespa e hara ter you type is onsidered to be the start of the value
you wish to give for pqr. You may type several non whitespa e hara ters as value if
appropriate. After typing the desired value you must type a whitespa e hara ter (often
newline) to signify that you have nished typing the value that you wanted. Let us onsider
an example. Suppose pqr has type int, then if you exe ute the above statement, and type
123 56
the spa es that you type at the beginning will be ignored, the value 123 will be stored into
pqr. This is be ause the spa e following 123 will serve as a delimiter. The 56 will be used
for a subsequent read statement, if any. Note further that the value you type will not be
re eived by your program unless you type a newline after typing the value. Thus to pla e
123 into pqr in response to the statement above, you must type a newline either immediately
following 123 or following 56.
If pqr was of any of the oating types, then a literal of that type would be expe ted.
Thus we ould have typed in 6.022e23 or 1.5. If pqr was of type bool you may only type
0 or 1.
Reading into a har variable
You may not perhaps expe t what happens when you exe ute
har xyz;
in >> xyz;
In this ase the initial whitespa es that you type if any will be ignored, as dis ussed above.
Any non-whitespa e value is onsidered appropriate for the type har, so the rst su h value
will be a epted. The ASCII value of the rst non-whitespa e hara ter that you type will
be pla ed into xyz. Note that if you type 1, then xyz will be ome 49. This is be ause the
ASCII value of the hara ter '1' is 49. If you type the letter a, then xyz would get the value
97.
Abhiram Ranade, 2013. Do not distribute 52
Reading several values
If you wish to read values into several variables, you an express it in a single statement.
in >> pqr >> xyz;
This is equivalent to writing in >> pqr; in >> xyz;.

3.1.5 Printing
If you print a variable rst of type bool, short, int or long, writing
out << rst << endl;
its value will be printed. A minus sign will be printed if the value is negative. The nal endl
will ause a newline to follow.
If you print a oating type variable, then C++ will print it in what it onsiders to be
the best looking form: as a de imal fra tion or in the s ienti format.
Printing a har variable
Consider the following ode.
har xyz=97;
out << xyz << endl;
This will ause that hara ter whose ASCII value is in xyz to be printed. Thus in this ase
the letter a will be printed. Following that a newline will be printed, be ause of the endl at
the end of the statement.
Printing several values
The two previous statements above an be ombined into a single statement if you wish.
out << rst << endl << xyz << endl;

3.1.6 Exa t representational parameters


Table 3.1 mentions the indi ative sizes of the di erent data types. You an nd the exa t
number of bytes used by your ompiler by using the sizeof ommand in your program:
out << sizeof(int) << endl;
Or sizeof(double) and so on as you wish. You an also write sizeof(variable-name) to
get the number of bytes used for the variable variable-name.
You an also determine the largest or smallest (magnitude) representable numbers in the
di erent types. Say for float, the expression numeri limits<float>::max() gives the
value of the largest oating point number that an be represented. Please do not worry
about the ompli ated syntax of this expression. By using other types instead of float or
by using min instead of max, you an get the minimum/maximum values for all types. In
order to use this fa ility, you need to put the following line at the top of your le (before or
after other #in lude statements):
Abhiram Ranade, 2013. Do not distribute 53
#in lude <limits>
We will see the exa t a tion of this line later.

3.2 Arithmeti and assignment


We an perform arithmeti on the values stored in variables in a very intuitive manner,
almost like we write algebrai expressions. The values resulting from evaluating an arithmeti
expression an be stored into a variable by using an assignment statement.
The notion of expressions is similar to that in Algebra. If you have an algebrai expression
x  y + p  q , its value is obtained by onsidering the values of the variables x; y; p; q , and
performing the operations as per the usual pre eden e rules. In a similar manner you an
write expressions involving C++ variables, and the value of the expression is obtained by
similarly onsidering the values of the variables and performing operations on them, with the
same rules of operator pre eden e. One di eren e is that often in Algebra the multipli ation
operator is impli it, i.e. xy means x multiplied by y. In a C++ expression, we need to
expli itly write the multipli ation operator, whi h is *. All the arithmeti operators +,-,*,/
are allowed. Multipli ation and division have equal pre eden e, whi h is higher than that
of addition and subtra tion whi h have the same pre eden e. Some additional operators are
also allowed, as will be dis ussed later. Among operations of the same pre eden e, the one
on the left is performed rst, e.g. 5-3+9 will mean 11. We an use bra kets to enfor e the
order we want, e.g. write 5-(3+9) if we want this expression to evaluate to -7. If we had
C++ variables x,y,p,q, then the expression orresponding to the algebrai expression above
would have to be written as x*y+p*q. Note that when you use a variable in an expression,
it is your responsibility to ensure that the variable has been assigned a value earlier.
An expression auses a sequen e of arithmeti operations to be performed, and a value
to be omputed. However, the omputed value is lost unless we do something with it. One
possibility is to store the omputed value in some variable. This an be done using an
assignment statement. The general form of an assignment is:
variable = expression;
where variable is the name of a variable, and expression is an expression as des ribed
above. Here is an example.
int x=2,y=3,p=4,q=5,r;
r = x*y + p*q;
This will ause r to get the value of the spe i ed expression. Using the values given for the
other variables, the expression is simply 2*3+4*5, i.e. 26. Thus r will get the value 26.
We ould also print out the value of the expression by writing
out << x*y+p*q << endl;
Note that when you use a variable in an expression, you must have assigned it a value
already, say by initializing it at the time of de ning it, or by reading a value into it from
the keyboard, or in a previous assignment statement. If this is not done, the variable will
Abhiram Ranade, 2013. Do not distribute 54
still ontain some value, only you dont know what value. If an unknown value is used in a
omputation, the result will of ourse be unpredi table in general.
Note that the operator = is used somewhat di erently in C++ than in mathemati s. In
mathemati s a statement r = x*y + p*q; asserts that the left hand side and right hand
side are equal. In C++ however, it is a ommand to evaluate the expression on the right
and put the resulting value into the variable named on the left. After the assignment the
values of the expressions on either side of the = operator are indeed equal if we onsider r
on the left hand side to be a trivial expression.
Note however, that we annot write x*y + p*q = r; be ause we require the left hand
side to be a variable, into whi h the value of the expression on the right hand side must be
stored.
The rule des ribed above makes it perfe tly natural to write a statement su h as:
p = p + 1;

This is meaningless in mathemati s; in C++ however it just says: evaluate the expression on
the right hand side and put the resulting value into the variable named on the left. Assuming
p is as in the ode fragment given earlier, its value is 4. Thus in this ase the value 4+1=5
would be put in p. Note that a statement su h as p + 1 = p; is illegal { the left hand side
p + 1 does not denote a variable.

3.2.1 Integer division and the modulo operator %


In C++, when one integer value is divided by another, the result is de ned to also be the
largest integer no larger than the quotient. Thus if you write
int m=100, n=7, p, q;
p = m/n;
q = 35/200;

the variables p and q would respe tively get the values 14 and 0. In other words, we only
get the integer part of the quotient.
If you wish to get the remainder resulting when one integer divides another you use the
% operator. Thus the expression m % n evaluates to the remainder of m when divided by n,
where m,n must have an integral type. The operator % has the same pre eden e as *, /.
Here is a ode fragment that reads in a duration given in se onds and prints out the
equivalent duration in hours, minutes, and se onds.
out <<"Give the duration in se onds: ";
int duration; in >> duration;
int hours, minutes, se onds;
hours = duration/3600;
minutes = (duration - hours*3600)/60;
se onds = duration % 60;
out <<"Hours: "<< hours <<", Minutes: "
<< minutes <<", Se onds: "<< se onds << endl;
Abhiram Ranade, 2013. Do not distribute 55
If you run this ode, and type 5000 when asked, you would get the following output as
expe ted:
Hours: 1, Minutes: 23, Se onds: 20

3.2.2 Subtleties
The assignment statement is somewhat tri ky. The rst point on erns the oating point
representations. Both, float and double are impre ise representations, where the signi and
is orre t only to a xed number of bits. So if an arithmeti operation a e ts less signi ant
bits, then the operation will have no e e t. As an example, onsider the following ode.
float w, y=1.5, avogadro=6.022E23 ;
w = avogadro + y;

What is the value of w? Suppose for a moment that we pre isely al ulate the sum avogadro
+ y. The sum will be
602200000000000000000001:5
We will have a problem when we try to store this into a float type variable. This is be ause
a float type variable an only stores signi ands of 24 bits, or about 7 digits. So in order
to store, we would treat everything beyond the most signi ant 7 digits as 0. If so we would
get
602200000000000000000000
This loss of digits is alled round-o error. After the round o , this an now t in a float,
be ause it an be written exa tly as 6.022E23. Net e e t of the addition: nothing! The
variable w gets the value avogadro even though you assigned it the value avogadro + 1.5.
This example shows the inherent problem in adding a very small float value to a very large
float value.
Some subtleties arise when we perform an arithmeti operation in whi h the operands
have di erent types, or even simply if you store one type of number into a variable of another
type. C++ allows su h operations, and ould be said to perform su h a tions reasonably
well. However, it is worth knowing what exa tly happens.
Suppose we assign an int expression to a float variable, C++ will rst onvert the
expression into the oating point format. An int variable will have 31 bits of pre ision
ex luding the sign, whereas a float variable only has 24 bits or so. So essentially some
pre ision ould be lost. There ould be loss of pre ision also if we assign a float expression
to an int variable. Consider:
float y = 6.6;
int x = y;

The value 6.6 is not integral, so C++ tries to do the best it an: it keeps the integer part. At
the end, x will equal 6. Basi ally, when a oating value is to be stored into an integer, C++
uses trun ation, i.e. the fra tional part is dropped. You might want the assigned value to
be the losest integer. This you an obtain for yourself by adding 0.5 before the assignment.
Thus if you write x=y+0.5;, then x would be ome 7, the integer losest to y. Note that some
Abhiram Ranade, 2013. Do not distribute 56
pre ision ould be lost when you store a value from a double (53 bits of pre ision) into a
oat (24 bits of pre ision). Over ow is also possible, as dis ussed later.
When we perform an arithmeti operation on operands of the same type the result is also
omputed to be of the same type. If your program asks to perform arithmeti operations on
operands of di erent types, then the operands are rst onverted by C++ so that they have
the same type. The rules for this are fairly natural. C++ always onverts less expressive
types to more expressive ones, where unsigned integral types are deemed less expressive than
signed integral types, whi h in turn are deemed less expressive than the oating types. If the
two types di er in size, then the smaller is onverted to have a larger size. As an example,
suppose we have an arithmeti expression var1 op var2, where var1 is int and var2 is
float. Then var1 will be onverted to float, and the result will also be float. If var1,
var2 are long, int, then var2 will be onverted to long. If the operands are of type
float, long long then both will be onverted to double, and so on. After the expression
is evaluated, it may either itself form an operand in a bigger expression, or it might have to
be stored into a variable. In both ases, there may have to be a further type onversion.
Literals also have a type asso iated with them. An integer literal like 35 is onsidered to
be of type int, and a oating literal like 100.0 is by default onsidered to be of type double.
You an spe ify literals of spe i types by atta hing the suÆxes L,F,U whi h respe tively
stand for long, oat, unsigned. Thus if you write 100LU, it will be interpreted as a literal of
type long unsigned, having the value 100.
It is important to be areful with division.
int x=100, w;
float y,z;
y = 360/x;
z = 360.0/x;
w = 360.0/x;

As per the rules stated, 360/x will be evaluated to have an integer value sin e both operands
are integer. Thus the exa t quotient 3.6 will be trun ated to give 3. This value will be stored
(after onversion to the oating point format) into y. In the next statement, 360.0/x the
rst operand is double, hen e the result will be evaluated as a double, i.e. 3.6. This value
will be stored in z. In the nal statement, the value of the expression will indeed be 3.6,
however be ause w is of type int, there will have to be a type onversion, and as a result
the value stored in w will be just 3.
Note nally that if the dividend and the divisor are of integral types, and the divisor
is 0, then an error will be reported when su h an operation happens during exe ution, and
the program will stop with a message. Something di erent happens for oating types, as
dis ussed in Se tion 3.2.4.
3.2.3 Over ow and arithmeti errors
For ea h numeri al data type, we have mentioned a ertain largest possible and smallest
possible value that an be represented. While performing al ulations, the results an go
outside this allowed range. In this ase, what exa tly happens is handled di erently for
di erent types.
Abhiram Ranade, 2013. Do not distribute 57
For the unsigned data types, the rule is that arithmeti is performed modulo 2n, where
n is the number of bits used. So for example if you add up two short numbers, both
65535, then the result will be (65535+65535) mod 65536 = 65534, where you may note that
2 = 65536.
16

For signed integer types, the language does not spe ify what must happen. In other
words, you as a programmer must be areful to ensure that the numbers stay within range.
3.2.4 In nity and not a number
Most C++ ompilers support the IEEE oating point standard. With su h ompilers, some-
thing quite interesting happens if the result of a oating type omputation be omes too large
to represent, e.g. if you try to ompute the square of Avogadro's number and try to store it
into a float variable. In su h ases a spe ial bit pattern gets stored in the variable. This bit
pattern behaves like in nity for all subsequent omputation. By this, we mean that anything
added to in nity remains in nity, and so on. If you try to print out this pattern, quite likely
inf would get printed. Thus, you at least get some indi ation that some over ow o urred
during omputation. You also get the result inf when you divide a positive oating value
by 0. Likewise you get -inf when you divide a negative oating number by 0.
If the dividend and the divisor are both zeroes, represented as oating point numbers,
then you get another spe ial bit pattern whi h will likely be printed as nan. This pattern is
meant to represent the result of an unde ned operation, nan is an abbreviation for \not a
number". If you happen to use a variable or an expression of value nan in any operation, the
result will also be nan. Note that taking the square root of a negative number also produ es
nan.
We will see later that it is a tually useful to use in nities in our omputations. In your
C++ programs you an refer to 1 using the name HUGE VAL. Thus you may write:
double x = HUGE_VAL;

3.2.5 Expli it type onversion


It is possible to onvert an expression exp of numeri al type T1 to an expression of type T2
by writing either
T2(exp)

or
(T2) exp
This latter form is a lega y from the C language. The type onversion rules as des ribed
earlier apply, e.g. int(6.4) would evaluate to the integer value 6.
3.2.6 Assignment expression
It turns out that C++ allows you to write the following ode.
Abhiram Ranade, 2013. Do not distribute 58
int x,y,z;
x = y = z = 1;

This will end up assigning 1 to all the variables. This has a systemati explanation as follows.
Any assignment, say z = 1, is also an expression in C++. Not only is the assignment
made, but the expression stands for the value that got assigned. Further, the asso iativity of
= is right-to-left, i.e. given an expression x = y = z = 1, the rightmost assignment operator
is evaluated rst. This is di erent from the other operators you have seen so far, su h as the
arithmeti operators, in whi h the evaluation order is left to right. Thus, the our statement
x = y = z = 1; is really to be read as
x = (y = (z = 1));
Now the expression inside the innermost parentheses, z = 1 is required to be evaluated rst.
This not only puts the value 1 into z, but itself evaluates to 1. Now the statement e e tively
be omes
x = (y = 1);
The exe ution ontinues by setting y to 1, and then x to 1.

3.3 Examples
We onsider some simple examples of using the data-types and assignment statements. These
do not in lude the bool type whi h is onsidered in Se tion 6.7.
Here is a program that reads in the temperature in Centigrade and prints out the equiv-
alent temperature in Fahrenheit.
main_program{
double entigrade, fahrenheit;

out << "Give temperature in Centigrade: ";


in >> entigrade;

fahrenheit = 32.0 + entigrade * 9.0/5.0;


out << "Temperature in Fahrenheit: " << fahrenheit << endl;
}
Note that the operator + is exe uted last be ause it has lower pre eden e than * and /. The
operator * exe utes before / be ause it appears to the left. Note we ould have written 9
instead of 9.0. This is be ause that while multiplying entigrade, it would get onverted
to a double value anyway, sin e entigrade is double. Similarly we ould have written 5
and 32 instead of 5.0 and 32.0. But what we have written is preferable be ause it makes it
very lear that we are engaging in oating point arithmeti .
In the next program you are expe ted to type in any lower ase letter, and it prints out
the same letter in the upper ase.
Abhiram Ranade, 2013. Do not distribute 59
main_program{
har small, apital;

out << "Type in any lower ase letter: ";


in >> small;

apital = small + 'A' - 'a';

out << apital << endl;


}
When the statement in >> small; exe utes, the ASCII value of the letter typed in by the
user is pla ed in small. Suppose as an example that the user typed in the letter q. Then
its ASCII value, 'q' is pla ed in small. This value happens to be 113. To understand the
next statement, we need to note an important property of the ASCII odes.
The lower ase letters a-z have onse utive ASCII odes. The upper ase letters A-Z also
have onse utive ASCII odes. From this it follows that for all letters, the di eren e between
the ASCII ode of the upper ase version and the lower ase version is the same. Further,
be ause 'A' and 'a' denote the integers representing the ASCII odes of the respe tive letters,
'A'-'a' merely gives the numeri al di eren e between the ASCII odes of upper ase and lower
ase of the letter a. But this di eren e is the same for all letters. Hen e given the ASCII
ode value for any lower ase letter, we an add to it 'A' - 'a', and this will give us the ASCII
ode of the orresponding upper ase letter. So this value gets pla ed in apital, whi h
when printed out displays the a tual upper ase letter.
To omplete the example, note that the ASCII ode of 'A' is 65. Thus 'A'-'a' is -32.
Sin e small ontains 113, apital would get 113 - 32, i.e. 81. This is indeed the ASCII ode
of Q as required.
Note that the digits '0', '1', '2', : : :, '9' also have onse utive ASCII odes.

3.4 Assignment with repeat


What do you think happens on exe uting the following pie e of ode?
main_program{
turtleSim();
int i = 1;
repeat(10){
forward(i*10); right(90);
forward(i*10); right(90);
i = i + 1;
}
wait(5);
}
Imagine that you are the omputer and exe ute the ode one statement at a time. Write
down the values of di erent variables as you go along, and draw the lines tra ed by the turtle
Abhiram Ranade, 2013. Do not distribute 60
as it moves. You will probably be able to gure out by exe uting 2-3 iterations. It is strongly
re ommended that you do this before reading the explanation given next.
In the rst iteration of the repeat, i will have the value 1, and this value will in rease
by 1 at the end of ea h iteration. The turtle goes forward 10*i, i.e. a larger distan e in ea h
iteration. As you will see, the turtle will tra e a \spiral" made of straight lines.
We next see another ommon but important intera tion of the assignment statement and
the repeat statement. Consider the following problem. We want to read some numbers,
from the keyboard, and print their average. For this, we need to rst nd their sum. This
an be done as follows.
main_program{
int ount;
out << "How many numbers: ";
in >> ount;

float num,sum=0;
repeat( ount){
out << "Give the next number: ";
in >> num;
sum = sum + num;
}

out << "Average is: ";


out << sum/ ount;
out << endl;
}
The statement sum = sum + num; is exe uted in ea h iteration, and before it is exe uted,
the next number has been read into num. Thus in ea h iteration the number read is added
into sum. Thus in the end sum will indeed ontain the sum of all the numbers given by the
user.
3.4.1 Programming Idioms
There are two important programming idioms used in the programs of the previous se tion.
The rst idiom is what we might all the sequen e generation idiom. Note the value of
the variable i in the rst program. It started o as 1, and then be ame 2, then 3, and so
on. As you an see, by hanging the starting value for i and adding a di erent number to
i inside the loop instead of 1, we ould make i take the values of any arithmeti sequen e
(Exer ise 7). By hanging the operator to * instead of +, we ould make the values form a
geometri sequen e if we wished.
The se ond idiom is what we might all the a umulation idiom. This was seen in the
se ond program. The variable sum was initialized to zero, and then the number read in ea h
iteration was added to the variable sum. The variable sum was thus used to a umulate the
values read in ea h iteration. Stating this di erently, suppose the number of numbers read
Abhiram Ranade, 2013. Do not distribute 61
is n, and suppose the values read were v ; : : : ; vn. Then after the exe ution of the loop in
1
the se ond program the variable sum has the value:
0 + v + v +    + vn
1 2

Here we have written 0+ expli itly to emphasize that the value al ulated a tually also
depends on the value to whi h sum was initialized, and that happened to be zero, but it is
a hoi e we made.
You might wonder whether this idea only works for addition or might work for other
operators as well. For example C++ has the ommand max, where max(a,b) gives the
maximum of the values of the expressions a,b. Will using max help us ompute the value
of the maximum of the values read? In other words, what would happen if we de ned a
variable maximum and wrote
maximum = max(maximum, num);
instead of sum = sum + num;? For simpli ity, assuming n = 4 and also assuming that
maximum is initialized to 0 just as sum was, the value taken by maximum at the end of the
repeat will be:
max(max(max(max(0; v ); v ); v ); v )
1 2 3 4

Will this return the maximum of v ; v ; v ; v ? As you an see this will happen only if
1 2 3 4
at least one of the numbers is positive. If all numbers are negative, then this will return
0, whi h is not the maximum. Before we abandon this approa h as useless, note that we
a tually have a hoi e in de iding how to initialize maximum. Clearly, we should initialize it
to as small a number as possible, so that the values vi annot be even smaller. We know
from Se tion 3.1.6 that it suÆ es to hoose -numeri limits<float>::max(). Thus our
initialization be omes:
maximum = - numeri _limits<float>::max();
whi h we put in pla e of the statement sum=0; in the program.
There is another way to do this also, whi h you might nd simpler. We ould merely
read the rst value of num, and assign maximum to that. Thus the program just to al ulate
the maximum of a sequen e of numbers will be as follows. Note that we now repeat only
ount-1 times, be ause we read one number earlier.
main_program{
int ount;
out << "How many numbers: ";
in >> ount;

float num,maximum;

out << "Give the next number: ";


in >> maximum;

repeat( ount-1){
Abhiram Ranade, 2013. Do not distribute 62
out << "Give the next number: ";
in >> num;
maximum = max(maximum,num);
}
out << "Maximum is: " << maximum << endl;
}
This program does not behave identi ally to the program sket hed earlier, i.e. obtained by
initializing maximum to - numeri limits<float>::max(). The exer ises ask you to say
when the programs might di er, and whi h one you prefer under what ir umstan es.
3.4.2 Combining sequen e generation and a umulation
Often we need to ombine the sequen e generation and a umulation idioms.
Suppose we want to ompute n fa torial, written as n!, whi h is just short hand for the
produ t n  (n 1)  (n 2)      2  1. How an we do this?
The key point to note is that we merely need to take the produ t of the sequen e of
numbers 1; 2; : : : ; n 1; n, and this is a sequen e that we an generate. But if we an generate
a sequen e, then we an easily take its produ t, i.e. a umulate it using the multipli ation
operator.
main_program{
int n, fa =1, i=1;
in >> n;

repeat(n){
fa = fa * i; // sequen e a umulation
i = i + 1; // sequen e generation
}
out << fa << endl;
}
In the above program, if you ignore the statement fa = fa * i;, then we merely have
our sequen e generation program, with the sequen e 1 to n being generated in the values
taken by the variable i. However, the value generated in ea h iteration is being multiplied
into the variable fa whi h was initialized to 1. Hen e in the end the variable fa ontains
the produ t of the numbers from 1 to n, i.e. n! as we wanted. Note that the program also
works for n=0, sin e 0! is de ned to be 1.
The idioms of a umulation and sequen e generation are very useful, and very, very
ommonly used. They are used so ommonly that they will be ome se ond nature soon. We
see a more involved example in Chapter 4.

3.5 Some operators inspired by the idioms


Be ause sequen e generation and a umulation o ur ommonly in ode, C++ in ludes
operators that an be used to express these idioms more su in tly.
Abhiram Ranade, 2013. Do not distribute 63
3.5.1 In rement and de rement operators
A key statement in the sequen e generation idiom is i=i+1;. This tends to o ur quite
frequently in C++ programs. So a short form has been provided. In general you may write
C++;

whi h merely means C = C + 1;, where C is any variable. This usage is very useful.
For ompleteness, we des ribe some additional, possibly onfusing, feature of the ++
operator. Turns out that for a variable C, C++ is also an expression. It stands for the value
that C had before 1 was added to it. Thus if you wrote
int x = 2, y;
y = x++;
after exe ution y would be 2 and x would be 3. We re ommend that you avoid a statement
su h as y = x++; and instead write it as the less onfusing y = x; x++;. It is worth noting
that in the modern era programming is often done by teams, and so your ode will be read
by others. So it is good to write in a manner that is easy to understand qui kly.
The operator ++ written after a variable is said to be the (unary) post-in rement oper-
ator. You may also write ++C, whi h is the unary pre-in rement operator operating on the
variable C. This also auses C to in rease by 1. ++C also has a value as an expression: ex ept
the value is the new value of C. Thus if you wrote
int x = 2, y;
y = ++x;
both x,y would get the value 3. Again this will usually be better written as ++x; y = x;
(or for that matter as x++; y = x;) be ause it is less onfusing.
Likewise, C--; means C = C - 1;. This is also a very useful operator, and is alled the
post de rement operator. As an expression C-- has the value that C had before the de re-
mentation. Analogously, you have the pre-de rement operator with all similar properties.
Again, it is re ommended that you use the expression forms sparingly.
3.5.2 Compound assignment operators
The a umulation idiom ommonly needs the statement vname = vname + expr;, where
vname is a variable name, and expr an expression. This an be written in short as:
vname += expr;
The phrase vname += expr is also an expression and has as its value the value that got
assigned. Analogously C++ has operators *=, and -=, /=. These operators are olle tively
alled the ompound assignment operators.
The expression forms of the operator += and others are also quite rypti and hen e
onfusing. It is re ommended that you use these expression forms sparingly.
Abhiram Ranade, 2013. Do not distribute 64
3.6 Blo ks and variable de nitions
It turns out that most C++ programmers would write the average omputation program
from Se tion 3.4 slightly di erently, as follows.
main_program{
int ount;
out << "How many numbers: ";
in >> ount;

float sum=0;
repeat( ount){
out << "Give the next number: ";
float num; // defined inside the loop
in >> num;
sum = sum + num;
}

out << "Average is: ";


out << sum/ ount;
out << endl;
}
As you an see, the only di eren e is that the variable num is de ned inside the loop rather
than outside. We rst explain how the variable de nition is exe uted in the new program.
As you might guess, the variable indeed gets reated when ontrol rea hes the de nition
statement. From the time of reation, the variable is available to the program, until the time
the ontrol rea hes the end of the loop body in the urrent iteration. In other words, the
variable is destroyed when the ontrol rea hes the end of the body! Thus, in ea h iteration
of the loop, the variable is reated and destroyed. Of ourse, destroying a variable is only
notional, the omputer merely assumes that the memory that was given is now available for
use. It should also be noted that the variable annot be used outside the repeat loop, or
before its de nition inside the loop.
Experien ed programmers prefer to write the average omputation ode in the new style,
be ause in this the de nition of num is pla ed lose to its use. Pla ing de nitions lose to
the use makes it easier to read the program, espe ially if it has many variables and the loop
bodies are large.
Next we will state the general rules for all this. First we need the notion of a blo k.
3.6.1 Blo k
The region of the program from an opening bra e, f, to the orresponding losing bra e,
g, is alled a blo k. Thus the entire program forms a blo k, and the body of a repeat also
forms a blo k, whi h is ontained inside the blo k onsisting of the entire program. If there
is a repeat inside a repeat, then the blo k orresponding to the body of the former is
ontained inside the blo k asso iated with the latter. As you an see, two blo ks must either
Abhiram Ranade, 2013. Do not distribute 65
be ompletely disjoint, or one of them must be ompletely ontained in the other. It is also
useful to de ne the parent blo k of a variable de nition: it is the innnermost blo k in whi h
the variable is de ned.
3.6.2 General prin iple 1
Now, we an restate more formally what we stated earlier. When ontrol rea hes a variable
de nition, the orresponding variable is reated. The variable is destroyed when the ontrol
leaves the parent blo k of the de nition. The variable is potentially available for use in the
region of the program starting at the point of its de nition, and going to the end of its parent
blo k. This region of the program is alled the s ope of the de nition.
We have already dis ussed how this prin iple applies to the variable num of the program
given above.
The prin iple also applies to the variable sum in the program. Its parent blo k is the main
program itself, and indeed, the entire portion of the program from the point of its de nition
to the end of the program an refer to the variable sum.
3.6.3 General prin iple 2
The prin iples in giving names to variables and using the names, are somewhat similar to
the way in whi h we give names to human beings.
Let us rst dis uss how we name human beings. Ideally, you might think that we should
insist that all human beings be given di erent names. But of ourse, this does not happen.
It is perfe tly possible that there exist two families in Mumbai both of whi h name their son
Raju. In that ase whenever a referen e is made to \Raju" in either family, it is deemed to
refer to the son in that family. There is no onfusion. Noti e however, that usually the same
name is not given to two hildren in the same family.
As another example, onsider the name Manmohan. In most families in India, the name
would be onsidered to be referring to the Prime Minister of India. Suppose now that a
ertain family de ides to name their son \Manmohan". In this family, after the birth of the
son, if anyone speaks of Manmohan, it would probably be onsidered as referring to the son.
You ould say that the son \overshadows" the Prime Minister in this family.
Variable naming in C++ is almost as exible as naming of human beings, in luding the
idea of shadowing. The analogue of the family is a blo k of the program.
In a C++ program, it is possible to use the same name in several variable de nitions.
However, it is ne essary that the de nitions have di erent parent blo ks. Even if there are
many variable de nitions for the same name, the rules for reating and destroying variables
remain the same. A variable is reated when the de nition is en ountered during exe ution,
and is destroyed when its parent blo k is exited. Or alternately, a variable is reated when
ontrol enters the s ope of the de nition and is destroyed when ontrol leaves the s ope of
the de nition. Suppose now that the ontrol has entered the s ope of a ertain de nition
that reates a variable Q. As the exe ution pro eeds, but before the variable is destroyed,
suppose we have another de nition, also of variable Q. Now a se ond variable named Q will
be reated and while ontrol is inside the s ope of the se ond de nition, the se ond variable
will shadow the rst variable. In other words, inside the s ope of the se ond de nition the
Abhiram Ranade, 2013. Do not distribute 66
name Q will not refer to the rst variable. It will instead refer to the se ond variable { unless
that of ourse is shadowed by a third de nition of Q.
Here are some examples.
main_program{
int sum=0;
repeat(5){
int num; // statement 1
in >> num;
sum += num;
}
out << sum << endl;
int prod=1;
repeat(5){
int num; // statement 2
in >> num;
prod *= num;
}
out << prod << endl;
}
In this ase the referen es to num in the rst loop are in the s ope of the de nition in
statement 1 (and of no other de nition), and hen e refer to the variable reated in statement
1. Similarly the referen es to num in the se ond loop are in the s ope of the de nition in
statement 2 (and of no other de nition), and hen e refer to the variable reated in statement
2. This is what you would intuitively expe t, and indeed the program will ompute the sum
of the rst 5 numbers that it reads, and the produ t of the next 5.
Here is an example of a program in whi h there is shadowing.
main_program{
int p=10; // statement 3
repeat(3){
out << p << endl; // statement 4
int p=5; // statement 5
out << p << endl; // statement 6
}
out << p << endl; // statement 7
}
In this program, the o uren e of p in statement 6 is in the s ope of the de nitions in
statements 3 and 5, with the latter shadowing the former. Thus the name p in statement 6
refers to the variable reated in statement 5. However, note that the statements 4 and 7 are
only in the s ope of the de nition in statement 3. Thus the name p in this statements refers
to the de nition in statement 3.
Thus when ontrol arrives at statement 3, a variable p is reated. When ontrol arrives
at statement 4, the value of this p, 10, is printed. When ontrol arrives at statement 5, a new
variable also named p will be reated, and will start shadowing the de nition of statement
Abhiram Ranade, 2013. Do not distribute 67
3. At the end of the loop the variable reated in statement 5 will be destroyed. Thus when
ontrol rea hed statement 7, the variable reated in statement 6 will have been destroyed,
and the statement is in the s ope only of the de nition in statement 3. Thus the referen e
to p in statement 7 will be onsidered to be to the variable p de ned in statement 3. Thus
statement 7 will ause 10 to be printed. Thus the entire ode when exe uted will ause the
sequen e of numbers 10, 5, 10, 5, 10, 5, 10 to be printed.

3.7 Con luding remarks


The initial part of most programs onsist of statements whi h reserve memory in whi h to
store data. Su h statements are alled variable de nition statements. A de nition reserves
the spa e and also gives it a name. The reserved spa e, together with its name, is said to
onstitute a variable, and the data stored in the variable is said to be the value of the variable.
Of ourse, what is stored in memory is always a sequen e of bits. The value represented by
the bit sequen e depends upon how we interpret the bits, whi h is spe i ed by the type of
the variable. As dis ussed in Chapter 2, it is possible that the same pattern of 32 bits might
mean one value for a variable of type unsigned int, another for a variable of type (signed)
int, and yet another for a variable of type float.
When we de ne a variable, it is always for some spe i purpose. So it is strongly
re ommended that the name hosen for the variable re e t that purpose. Also, along with
the de nition, it is useful to write additional omments whi h explain its purpose in more
detail if ne essary.
When we refer to the name of a variable in a program, we almost always refer to the
value stored in the variable, ex ept when the name appears on the left side of an assignment
statement, when it refers to the memory asso iated with the variable, i.e. whatever is the
value on the right hand side is to be stored in this memory. Perhaps this observation is
useful to prevent being onfused by statements su h as p = p + 1; whi h are in orre t
in mathemati s but whi h are meaningful in omputer programs. We also noted that the
assignment statement is somewhat subtle, be ause of issues su h as rounding, and onverting
between di erent types of numbers.
The assignment statement also plays a entral role in two important programming id-
ioms: sequen e generation, and a umulation. We saw a number of operators whi h an be
onsidered to have been inspired by these idioms.
We noted that it is onvenient if a variable is de ned lose to the point in the program
where it is used. This led us to notion of the s ope of a variable, i.e. the region of the
program where the variable an be referred to, and also the notion of shadowing.

3.8 Exer ises


1. What is the value of x after the following statements are exe uted? (a) x=22/7;
(b) x=22.0/7; ( ) x=6.022E23 + 1 - 6.022E23 (d) x=6.022E23 - 6.022E23 + 1
(e) x=6.022E23 * 6.022E23. Answer for three ases, when x is de ned to be of type
int, float, double. Put these statements in a program, exe ute and he k your
on lusions.
Abhiram Ranade, 2013. Do not distribute 68
2. For what values of a,b, will the expressions a+(b+ ) and (a+b)+ evaluate to di erent
values?

3. I want to ompute the value of 100
=      . I have many hoi es in
100 99 98 97 96 95

performing this omputation. I an hoose the order in whi h to perform the multipli-
6 1 2 3 4 5 6

ations and divisions, and I an hoose the data type I use for representing the nal
and intermediate results. Here is a program whi h does it in several ways. Guess whi h
of these are likely to give the orre t answer, nearly the orre t answer, or the wrong
answer. Then run the program and he k whi h of your guesses are orre t.
main_program{
int x = 100 * 99 * 98 * 97 * 96 * 95/ (1 * 2 * 3 * 4 * 5 * 6);
int y = 100/1 * 99/2 * 98/3 * 97/4 * 96/5 * 95/6;
int z = 100/6 * 99/5 * 98/4 * 97/3 * 96/2 * 95/1;

int u = 100.0 * 99 * 98 * 97 * 96 * 95/ (1 * 2 * 3 * 4 * 5 * 6);


int v = 100.0/1 * 99/2 * 98/3 * 97/4 * 96/5 * 95/6;
int w = 100.0/6 * 99/5 * 98/4 * 97/3 * 96/2 * 95/1;

out << x << " " << y << " " << z << endl;
out << u << " " << v << " " << w << endl;
}

4. What will be the e e t of exe uting the following ode fragment?


float f1, f2, entigrade=100;
f1 = entigrade*9/5 + 32;
f2 = 32 + 9/5* entigrade;
out << f1 << ' ' << f2 << endl;

har x = 'a', y;
y = x + 1;
out << y << ' ' << x + 1 << endl;

5. Write a program that reads in distan e d in in hes and prints it out as v miles, w
furlongs, x yards, y feet, z in hes. Remember that a mile equals 8 furlongs, a furlong
equals 220 yards, a yard is 3 feet, and a foot is 12 in hes. So your answer should satisfy
d = (((8v + w)  220 + x)  3 + y )  12 + z , and further w < 8; x < 220; y < 3; z < 12.
6. What is the state of the omputer, i.e. what are the values of the di erent variables
and what is on the s reen, after 4 iterations of the loop of the spiral drawing program of
Se tion 3.4? Write down your answer without running the program. Then modify the
program so that it prints the values after ea h iteration and also waits a few se onds
so you an see what it has drawn at that point. Run the modi ed program and he k
whether what you wrote down earlier is orre t.
Abhiram Ranade, 2013. Do not distribute 69
7. Write a program that prints the arithmeti sequen e a; a + d; a + 2d; : : : ; a + nd. Take
a; d; n as input.
8. Write a program that prints out the geometri sequen e a; ar; ar ; : : : ; arn, taking a; r; n
2

as input.
9. Write a program whi h reads in side, nsquares, q. It should draw nsquares as many
squares, all with the same enter. The sidelength should in rease by q starting at side.
Repeat with the modi ation that the sidelength should in rease by a fa tor q.
10. Write a program whi h prints out the squares of numbers from 11 to 99.
11. What does the following program draw:
main_program{
turtlesim();
int i=0;

repeat(30){
left(90);
forward(200*sine(i*10));
forward(-200*sine(i*10));
right(90);
forward(10);
i++;
}
wait(5);
}

12. The ASCII odes for the digits 0 through 9 are 48 through 57. Suppose in the third
statement below, the user types in two digits. The ASCII odes for the digits will then
be pla ed in p,q. You are to ll in the blanks in the ode su h that dig1 gets the value
of the digit in p (not the value of its ASCII ode), and similarly dig2 should get the
value of the digit in q. Finally, the integer n should ontain the value of the number
in whi h p is in the tens pla e and q in the units pla e.
har p,q;
int dig1,dig2,n;
in >> p >> q; // equivalent to in >> p; in >> q;
dig1 = ...
dig2 = ...
n = ...

For example, if the user typed '1','2', then p,q will ontain the values 49,50. At the
end we would like dig1,dig2,n to be respe tively 1,2,12.
13. Write a program that takes as input the oordinates of two points in the plane and
prints out the distan e between them.
Abhiram Ranade, 2013. Do not distribute 70
14. Write the program for omputing the maximum of numbers as suggested initially in
Se tion 3.4.1, i.e. the one in whi h maximum was to be initialized to the value (-
numeri limits<float>::max()). Does this program behave identi ally (i.e. give the
same result for the same inputs) to the program given at the end of the Se tion 3.4.1?
If you think the programs behave di erently, state the inputs for whi h the programs
will behave di erently.
15. What does the following program ompute?
double x;
int n;
in >> x >> n;
repeat(n){
x = x * x;
}

16. Draw a smooth spiral. The spiral should wind around itself in a parallel manner, i.e.
there should be a ertain point alled \ enter" su h that if you draw a line going out
from it, the spiral should interse t it at equal distan es as it winds around.
Chapter 4

A program design example

In this hapter, we will use what we have learned to write a small program. This program
will be more omplex than all the programs you have seen so far. Indeed, the pro ess of
writing it will illustrate some important ideas in designing programs.
The problem we onsider is of nding the value of e, the base of the natural logarithm.
The number e an be written as the following in nite series.
e = nlim
1 + 1 + 1 + 1 ++ 1
!1 0! 1! 2! 3! n!
It turns out that the terms of the series de rease very fast, so that you get a good approximate
value by evaluating the series to a few terms.
The rst step in writing a program is to write down a spe i ation, by whi h we mean
a pre ise des ription of what is the input to the problem, and are the outputs, and what
it means for the output generated by the program to be orre t. Next omes the step of
designing the program itself. After that, you typi ally test the program, i.e. ompile and
run it on some inputs to see if it works orre tly. It might so happen, that the program
makes a mistake, in whi h ase you need to go ba k and try to nd what went wrong. This
step is often alled debugging, where a bug is a ommon euphemism for programming errors.
In addition to testing the program, you may formally reason for yourself that your program
is orre t.
We onsider these steps next.

4.1 Spe i ation


As mentioned above, the spe i ation for a program states learly what the input and the
output of the program will be. For our program to ompute e, what should the input be?
A natural possibility is to ask the user to state how mu h of the series should be summed.
Input to e omputation program: Integer n, where n  0.
Output from e omputation program: 1=0! + 1=1! + : : : + 1=n!.
You may have thought that the spe i ation for our program is \obvious". However,
note that the input n ould have been interpreted as the number of terms to whi h the series
71
Abhiram Ranade, 2013. Do not distribute 72
should be summed, in whi h ase the output would have to be 1=0!+1=1!+ : : : +1=(n 1)!.
So there appear to be two \obvious" ways of spe ifying the input. This may often happen.
In su h ases it doesnt really matter what we hoose, so long as we learly state what we
have hosen. A se ond point to be noted is that we have made a remark about the input
being required to be non-negative. In professional programs, you are expe ted to he k rst
whether the valid inputs are spe i ed by the user. In this small example we will ignore this
issue, but it is a point you should note. It is a good idea to tell the user of the program what
is a valid input and what isnt.
4.1.1 Examples
\Wait a minute", I would say. \Is there a parti ular example of this
general problem?"
Ri hard Feynman, Surely you'r joking Mr. Feynman

It is good to write down some examples of the spe i ation, i.e. for some spe i input
values what the output values ought to be. For our program, you may write: For input 0,
the output should be 1. For input 1, the output should be 2, for input 2, the output should
be 2.5. Writing down examples for es you to he k that you are being alert while writing
the spe i ation. Indeed, you may write the spe i ation as above, but in your mind might
still be thinking that n denotes the number of terms to be added. When you make up an
example, your onfusion will vanish.
Also, when your program is written, these examples an be used to test it.

4.2 Program design


The rst, extremely important, idea in designing programs is to think about how you would
solve the problem using a paper and pen il, without omputers. On e you are lear in your
mind how to solve a problem using paper and pen il, it often suÆ es to mimi the solution
on a omputer.
Quite likely, you have already tried to solve the problem using paper and pen il, if you
tried to onstru t examples as suggested in Se tion 4.1.1. You probably omputed the terms
of the series, and added them together as you went along. It is probably a good idea to
imagine yourself doing the al ulation for a large value of n, say n = 10. In this pro ess,
you will perhaps see that there is a general pattern, and you might also see how to do the
al ulation eÆ iently. In parti ular, suppose you have just al ulated the value of the term
1=3!, and then you go to the next term, 1=4!. Cal ulating 1=4! involves dividing 1 by the
numbers from 1 to 4, but of these divisions, you just did the divisions from 1 to 3 when you
al ulated 1=3!. So you an get the value of the term 1=4! simply by dividing 1=3! by 4. So
to al ulate any term 1=t!, you do just one additional division: you take the term 1=(t 1)!
that you previously omputed, and divide that further by t.
Next you need to gure out if there a repetitive pattern in your al ulations. If you nd
that you are performing similar steps repeatedly, you ould perhaps put those steps in a
repeat statement. Indeed, there is a pattern. The pro ess of al ulating the term 1=t! is
very similar to the pro ess of omputing 1=(t 1)!. So it would seem that you should indeed
Abhiram Ranade, 2013. Do not distribute 73
have a repeat loop. We want to al ulate the sum 1=0! + 1=1! + : : : + 1=n!, whi h has n + 1
terms, so it needs n additions. So presumably we will use n iterations of a repeat loop. And
our goal will be that we should have 1=0! + 1=1! + : : : + 1=t! al ulated after t iterations of
the loop. Thus in the tth iteration we will al ulate 1=t!, whi h we will then add to the sum.
The next step is to de ide what variables we need in the program. This step is a bit
tri ky. When you imagine yourself solving a problem using a paper and pen il, you just
keep on doing the additions or multipli ations (or divisions in this ase) using more paper
as ne essary. You may have written a lot of numbers on the paper as you worked, but that
doesnt mean you need a separate variable for holding ea h number that you might have
written. The key question to ask is: what data do we need at the beginning of the tth
iteration in order to perform the work that we planned for the iteration? We need a variable
to hold ea h su h pie e of data.
Clearly, we need to remember the sum of the series al ulated so far. Thus we should have
a variable result in whi h the sum omputed so far will be held. This variable should be of
a oating type. It is ustomary to use high pre ision, and so we will use the type double.
Further, we said that to al ulate 1=t! we need the value 1=(t 1)! whi h we al ulated in the
previous iteration. So we will have a variable term in whi h we will expe t to hold the value
1=(t 1)! at the beginning of the tth iteration. Finally in the tth iteration we need to divide
by t to get the new term value that needs to be added to result. In other words, we need
to know whi h iteration just nished. So we will use a variable i whi h will hold the value
t during the tth iteration. What we have de ided about the program an be summarized as
the following sket h.
main_program{
int n; in >> n;
int i = ...; // we fill in the blanks later.
double result = ..., term = ...;

repeat(n){
// Need ode to al ulate 1/0!+1/1!+...+1/t! in the tth iteration.
// At the beginning of the tth iteration
// i = t, term = 1/(t-1)!, result = 1/0!+1/1!+...+1/(t-1)!
}
out << result << endl;
}

Our plan, as stated in the omment, is a tually enough for us to omplete the program.
Imagine exe uting the program and entering the loop for the rst time. In our plan, this
orresponds to t = 1. So we want the variable i to be 1. Thus we must initialize it to 1
when we reate it. Se ond, we want term to have the value 1=0!, sin e t 1 = 0. Thus we
need to initialize term also to 1 = 1=0!. Likewise we also need to initialize result to 1.
Next we de ide pre isely what we need to do inside the loop. Imagine we are exe uting
the tth iteration of the loop. Our idea was to have result get the value 1=0! + : : : + 1=t! in
the tth iteration. Assuming everything has gone a ording to our plan so far, we will have
the values 1=0! + : : : + 1=(t 1)! in result and 1=(t 1)! in term. So we should have the
following statement inside the loop:
Abhiram Ranade, 2013. Do not distribute 74
/***************************************************
Program to al ulate e.
Cal ulates 1/0! + 1/1! + ... + 1/n!, for input n. n >= 0.

Abhiram Ranade, 24/2/13


***************************************************/
main_program{
int n; in >> n; // the last term to be added is 1/n!

int i=1; // ounts iterations of the loop


double term = 1.0; // for holding terms of the series
double result = 1.0; // Will ontain the final answer

repeat(n){ // Plan: When entering for the tth time, t = 1,2,..,n


// i = t, term = 1/(t-1)!, result = 1/0!+...+1/(t-1)!
result = result + term/i;
term = term/i;
i = i + 1;
}
out << result << endl;
}

Figure 4.1: A program to ompute e


result = result + term/i;

This will leave in result the value that we planned. Is this enough? No, in order to sti k
to our plan, in the t + 1th iteration, we will need to have the value t + 1 in the variable i,
and the value 1=t! in the variable term. This an be a heived by writing inside the loop:
term = term/i;
i = i + 1;

The omplete program is given in Figure 4.1. Note that we ould have written the three
statements inside the loop as result += term/i; term /= i; i++;. Indeed this is oftern
preferred. Note that the loop body ould also have been:
term = term/i;
result = result + term;
i = i+1;
In this the new value of result is al ulated using the old value of result and the new value
of term. In the version in Figure 4.1, the new values of all variables are al ulated from the
old values of all variables. Some may therefore nd the ode in Figure 4.1 to be simpler.
Abhiram Ranade, 2013. Do not distribute 75
4.2.1 Testing
The next step is to run the program and test if it really works. I ompiled and ran this
program supplying the values 1,2,3,4 for n, and it did print out the answers 2, 2.5, 2.667,
2.70833. If you did the al ulation by hand as suggested earlier, you will realize that these
values are indeed orre t. You ould also try some large value for n, say 10. When I did
this, I got the result 2.71828. Sin e e is a famous number, you should be able to get its value
from textbooks, and you will see that 2.71828 is the often quoted value.
4.2.2 Corre tness Proof
Testing is one way to he k if your program is orre t. However, testing does not really give
you a omplete guarantee of orre tness. You know what the program does for the input
values that you he ked; but how an you be sure that the program will not give a wrong
answer on other values?
One way to be sure is to prove that the program is orre t. This is often not pra ti al
for large programs. However, a proof an be written for our small program for omputing e.
We do this next. It will have some important lessons in general too.
You may be saying at this point, \But our program is obviously orre t, after all didn't
we design it so that the variable result has the desired value?" Unfortunately, it isnt so
simple: mistakes an reep in at any stage. Let me onfess that when I rst wrote the
program of Figure 4.1, I forgot to initialize the variable i. As a result, I was getting very
strange answers. Forgetting to initialize a variable is a \silly" mistake, but it is very easy to
make silly mistakes! This is an important humbling lesson that programming tea hes you.
Note that if our program is doing something serious, say ontrolling an air raft in ight, a
mistake of any kind an ause a rash. So we must learn to avoid even silly mistakes.
So as a ross he k, we will try to anyway prove the orre tness of the program after
we have nished writing it. In this proof, we will basi ally he k whether our program is
adhering to our plan, i.e. we on rm whether the variables indeed take the values we expe t
them to take. The proof is based on mathemati al indu tion. The indu tion hypothesis is
what we stated as our plan.
Indu tion Hypothesis: The values of i,term,result on the tth entry to the
loop are respe tively:
t; 1=(t 1)!;
1 +:::+ 1
0! (t 1)!
For the base ase, we onsider t = 1, i.e. the values on the rst entry. Substituting t = 1 in
the values in the Indu tion Hypothesis, we see that we want i,term,result to be all 1. But
the ode before the loop indeed initializes all these variables to 1. Thus we have established
the base ase. Note that when you do this part of the proof, you will dis over if you indeed
forgot to initialize any variable.
Next we will assume that the Indu tion Hypothesis is true on the tth entry, and show
that it must also hold on the t + 1th entry. Thus we need to prove:
Abhiram Ranade, 2013. Do not distribute 76
Indu tion step: The values of i,term,result on the t + 1th entry to the loop
are respe tively:
t + 1; 1=t!;
1 +:::+ 1
0! t!
To prove this, let us examine what happens during the tth iteration. First we exe ute result
= result + term/i;. At the beginning of the tth iteration we know by assumption that
result has the value 1=0! + : : : + 1=(t 1)!, and term the value 1=(t 1)!, and i the value
t. Thus the statement will ause 1=(t 1)! to be rst divided by t, and then added. Thus
result will get the value 1=0!+ : : : +1=(t 1)!+1=t!. This value will not hange during the
rest of the iteration, and hen e it will stay at the time of entering the loop for iteration t +1.
Thus we have proved the last part of the indu tion step. In the tth iteration we next exe ute
term = term/i;. The value of term and i on the tth entry are 1=(t 1)! and t respe tively.
Thus this statement would ause term to be ome 1=t!. This value will not hange during the
rest of the iteration, and hen e we have proved the se ond part of the indu tion step. The
last statement exe uted in the loop is i=i+1;. This will ause i to in rease to t + 1. This is
also the value we needed for the t + 1th iteration. Thus we have proved the indu tion step.
The indu tion is omplete.
On e we have proved the indu tion hypothesis, we know what the program will print.
The program will exe ute n iterations, where n was the value we typed in response to the
statement in >> n;. Thus the program will print the value the variable result at the end
of n iterations. We have argued above that this value will be 1=0! + : : : + 1=n!. Thus we
have in fa t proved that the program will work orre tly for all n.
4.2.3 Invariants
We ould have hara terized the values taken by the variables i, term, result in the
following manner
At the beginning or at the end of any iteration of the repeat loop, let
i; term; result be the values of the variables i, term, result. Then these values
satisfy the following relationships.
term = 1=(i 1)!; result = 1=0 + 1=1! +    + 1=(i 1)!
Noti e that this statement is independent of whi h iteration is being onsidered. Su h state-
ments are alled loop invariants, and these are more natural in other ontexts (Se tion 7.8.1).

4.3 Debugging
Unless you are one of the lu ky/ lever few, it is inevitable that the programs you write will
not work on the rst try. You will quite likely forget a semi olon or make some other mistake
be ause of whi h the ompiler will omplain. The ompiler will usually state the line number
in whi h the error is present, so generally it will be easy to orre t your mistake. But even
after your program ompiles orre tly, it is possible that it will produ e the wrong answers.
What do you do in that ase?
Abhiram Ranade, 2013. Do not distribute 77
Clearly you must go over your entire pro ess of design. Did you get the spe i ations
right? Have you forgotten to initialize a variable? After these basi he ks, you should
turn to the plan you wrote. In the plan you have essentially written down how you expe t
the variable values to hange in the di erent iterations. So onsider putting down print
statements whi h print out the values of the variables in ea h iteration. Then you will have
to al ulate by hand if they are as you expe t them to be. We will see some short uts for
this later, but basi ally this is what you need to do.
You may be tempted to say that your program is orre t but the omputer is making a
mistake { but omputers make mistakes so rarely that this possibility an be safely ignored.

4.4 Comments in the ode


We have remarked earlier that programs should be written not only so that they an be
ompiled and exe uted to solve problems, but also so that they an be easily understood by
other programmers.
There are several ways to make a program easier to understand. Most of these ways
involve putting in appropriate omments in ode. For example, the spe i ations should be
written down in the omments. Another way is to hoose good names for the variables so
that the names onvey the purpose. In addition, you ould write a omment along with the
de nition of the variable.
A very important aid to understandability is explaining the plan for a loop. The plan
should be des ribed in enough detail, so that it should be possible to understand the progress
made in ea h iteration towards the nal goal. Later on we will suggest other (related) ways
of explaining loops, e.g. invariants and potential (Se tion 7.8).

4.5 Con luding remarks


It is useful to summarize the main steps in designing a program.
Typi ally we start with an English language, semi-pre ise statement of the problem.
From this we rst generate a pre ise spe i ation, with lear hara terization of the input
and output. The general relationship between the input and the output must be stated, and
also some examples must be given.
As to designing the program, one strategy is to rst try to solve the problem using a
paper and pen il, without a omputer. Then we an mimi the paper-pen il solution on
a omputer. Note that there is a di eren e between being able to solve a problem and
ons iously knowing how you solve it. By \ ons iously knowing" we mean things su h as
being able to break up the solution into a sequen e of a tions, and also identifying patterns
in the sequen e. This is not diÆ ult, but requires some pra ti e and introspe tion. A related
issue is to be able to see \what do you need to do in general". In the omputation of e, we
needed to say that \in general, for any n, we need to have n iterations of the loop". This is
pretty mu h what you do in high s hool algebra when you say things su h as \if a pen osts
Rs. 5, then n pens ost Rs 5n". The ability to state things in general is ru ial to writing
programs!
Abhiram Ranade, 2013. Do not distribute 78
Next you need to identify repetitive patterns in the omputation, de ide what variables
to use, write down an overall plan and then write the a tual ode.
Testing your program is extremely important. We will say more on the subje t later.
However, for now, try testing on many values. As you an see, it is useful to work out what
results you expe t using pen il and paper, at least for a few ases.
We also gave an introdu tion to the pro ess of proving the orre tness of programs.
Proving programs to be orre t turns out to be too tedious for large programs. However,
for small programs, proving orre tness is very useful, and you will see several examples of
it in the book. When you prove a program, you are basi ally reasoning about how values
are assigned to the variables in the program so that the program slowly but steadily makes
progress towards omputing what it needs to. This progress is made pre ise in the plan (or
invariant as we will dis uss later on) that we wrote down. Even if you dont bother to prove
your programs orre t, we strongly re ommend that you write the plan for ea h non-trivial
loop in your program. Just the a t of writing the plan in detail will help you to get a orre t
program. The plan must be pla ed in the program as omments. This will also make your
program more understandable to others who might read it. Often, you an rst write the
plan and then the ode, as we just did.
Do everything you an that will in reases your on den e that your program is orre t.
Remember, a wrong program is not just useless, it is potentially dangerous.
4.5.1 A note on programming exer ises
Programming exer ises form a big part of learning to program. Programming annot be
learnt just by reading: pra ti e is extremely important. So please write as many programs
as possible. Follow the guidelines suggested in this hapter while writing programs.

4.6 Exer ises


1. Write a program to ompute the value of
( 1)k kr!!
r
X
D(r) =
k
=0

In identally, D(r) is the number of ways in whi h the numbers 1 through r an be


arranged in a sequen e su h that i is never in the ith position, for all i.
2. Here is an in nite produ t whi h an be shown to approa h 2= as the number of terms
in reases. p p p q2 + p2 + p2
2 = 2  2+ 2  
 2 2 2
Write a program that omputes the produ t of the rst n terms, where n is spe i ed as
input. You will need to spe ify what values your variables take after
q some t iterations.
p p
For this feel free to write something like \ numerator has value 2 + : : : + 2 with
p appearing t times". Write a proof of orre tness.
Abhiram Ranade, 2013. Do not distribute 79
main_program{ main_program{
int n, fa =1, i=2; int n, fa =1, i=1;
double e=1.0; double e=1.0;
in >> n; in >> n;

repeat(n){ repeat(n){
e = e + 1.0/fa ; e = e + 1.0/fa ;
fa = fa * i; fa = fa * i;
i = i + 1; i = i + 1;
} }
out << e << endl; out << e << endl;
} }

(a) (b)
Figure 4.2: One of these programs is in orre t.
3. Write a program to approximately ompute ex by adding rst 15 terms of the series
x0 x x x
1 2 3
ex =
0! 1! + 2! + 3! + : : :
+
4. Write a program that omputes the value of an nth degree polynomial A(x) = a + 0
a x + a x + : : : + an xn . Assume that you are given n then the value x, and then the
1 2
2

oeÆ ients a ; a ; : : : ; an.


0 1

5. Evaluate the polynomial, but this time assume that you are given the oeÆ ients in
the order an; an ; : : : ; a .
1 0

6. Figure 4.2 gives two programs to ompute e. One of them is in orre t. Find whi h
one. For the orre t program, give appropriate invariants and prove its orre tness.
7. Write a program whi h multiplies an n digit number M by a 1 digit number d, where
n ould be large, e.g. 1000. The input will be given as follows. First the user gives
d, then n and then the digits of M , starting from the least signi ant to the most
signi ant. The program must print out the digits of the produ t one at a time, from
the least signi ant to the most signi ant.
The program you write will likely perform about n multipli ation operations and a
similar number of other operations. There is a more eÆ ient way of writing this
program, i.e. using fewer operations for multiplying the same numbers M; d. Hint:
Ask the user to give several digits of M at a time.
Chapter 5

Simple pp graphi s

The graphi s ommands we introdu ed in Chapter 1 are fun, but quite limited. The more
general graphi s system that we dis uss in this hapter has many other features:
 Ability to have several turtles on s reen simultaneously, moving and drawing as desired.
 Ability to reate other shapes, e.g. lines, re tangles, ir les, polygons and text on the
s reen and move these shapes as desired. The shapes also have pens, so they an also
draw on the s reen if needed.
 Ability to hange attributes su h as olour, size of the various shapes.
 The graphi s window is asso iated with a Cartesian oordinate frame, and the position-
ing and movement of shapes an be spe i ed by giving the oordinates on the s reen,
rather than always having to be spe i ed relative to the position and the orientation
of the obje t in question.
 Elementary graphi al input. The user an li k on the graphi s window and the pro-
gram an wait for su h li ks and get the li k oordinates.
After dis ussing the di erent features of the graphi s system, we will give two examples.
The rst is somewhat simple: plotting the traje tory of a proje tile as it moves under the
in uen e of gravity. The se ond is more involved. In this the user an li k a set of points
on the s reen, and the program will draw the best t straight line through the points, under
a ertain measure of goodness.
You will note that it is easier to draw some kinds of pi tures by making a turtle tra e
over them. However, for many other kinds, it is more onvenient to spe ify the oordinates
dire tly. You will see examples of both in the hapters to ome.
In a later hapter, we will present some additional graphi s related features.

5.1 Overview
To a ess the more general graphi s fa ilities, it is more onvenient to use the ommand:
initCanvas();

80
Abhiram Ranade, 2013. Do not distribute 81
rather than turtleSim(). This opens a window, but does not reate a turtle at its enter.
Commands anvas width(), anvas height() return the width and height of the anvas
in pixels. You may also invoke the ommand as
initCanvas(name,w,h)
where name is a quoted string meant to be the name given for the anvas, and w,h should
indi ate the width and height you desire for the anvas window.
5.1.1 y axis goes downward!
A oordinate system is asso iated with the anvas window. You may nd it slightly unusual:
the origin is at the top left orner, and x oordinates in rease rightward, and y oordi-
nates downward. The oordinates are measured in pixels. Note however that internally,
simple pp onsiders the oordinates of obje ts to be real numbers of type double. These
real oordinates are onverted to integers only when needed for the purpose of displaying
the obje ts.

5.2 Multiple Turtles


We an reate multiple turtles very easily, by writing:
Turtle t1,t2,t3;
This will reate 3 turtles, respe tively named t1, t2, t3 at the enter of the window reated
using initCanvas(). Yes, the turtles will all be at the enter, sta ked one on top of the
other. We next see how we get them untangled.
The basi idea is: any ommand you used in Chapter 1 to a e t the turtle will also work
with these turtles, but you must say whi h turtle you are a e ting. For this, you must write
the ommand following the name of the turtle, the two joined together by a dot: \.". Thus,
to move turtle t1 forward by 100 steps, we merely write:
t1.forward(100);
Likewise, to turn t2 we would write
t2.left(90);
The same thing applies to other ommands su h as right, penUp, penDown.
Here is a program whi h will use 3 turtles to draw 3 o tagons, aligned at 120 degrees to
ea h other.
main_program{
initCanvas();
Turtle t1, t2, t3;

t2.left(120);
t3.left(240);
Abhiram Ranade, 2013. Do not distribute 82

repeat(8){
t1.forward(100);
t2.forward(100);
t3.forward(100);

t1.left(360.0/8);
t2.left(360.0/8);
t3.left(360.0/8);
}
wait(5);
}

5.3 Other shapes besides turtles


Three other shapes are allowed besides turtles: ir les and axis-parallel re tangles, and
straight line segments. Text is also onsidered to be a kind of shape. Later in Se tion 14.2.4
we will de ne a polygon shape.
5.3.1 Cir les
Cir les an be reated by writing:
Cir le 1( x, y,r);
Here, x, y,r must be numeri al expressions whi h indi ate the radius of the ir le, and
the x and y oordinates of its enter. The reated ir le is named 1.
5.3.2 Re tangles
An axis parallel re tangle is de ned as follows
Re tangle r1( x, y,Lx,Ly);
where x, y should give the oordinates of the enter, and Lx,Ly the width and height
respe tively. The reated re tangle has name r1.
5.3.3 Lines
A line segment an be de ned as:
Line line1(x1,y1,x2,y2);
This reates a line named line1 where x1,y1 are the oordinates of one endpoint, and x2,y2
the oordinates of the other.
Abhiram Ranade, 2013. Do not distribute 83
5.3.4 Text
If we want to write text on the s reen, it is also onsidered a kind of shape. The ommand
Text t1(x,y,message);
in whi h x,y are numbers and message is a text string an be used to write the message on
the s reen. So you might use the ommand Text txt(100,200,"C++"); to write the text
C++ on the s reen entered at the position (100,200). Another form is:

Text t2(x,y,number);
Here number an be a numeri al expression. The value of the expression at the time of
exe ution of this statement will omprise the text. It will be entered at the oordinates
(x,y).
The ommand textWidth an be used to nd the width of the given text in pixels. For
example textWidth("C++") returns the width of the text \C++" when drawn on the anvas.
The ommand textHeight() returns the height in pixels. Thus the following pie e of ode
an be used to write text and put a snugly tting box around it.
Text t(100,100,"C++ g++");
Re tangle R(100,100,textWidth("C++ g++"),textHeight());
If for some reason you wanted to know by how mu h the lower part of \g" des ends below the
line on whi h the text gets written, you an know this using the ommand textDes ent().

5.4 Commands allowed on shapes


Ea h shape mentioned above an be made to move forward and rotate, ex ept for Text
shapes, whi h annot be rotated. Ea h shape also has a pen at its enter whi h an be either
up or down.
In addition, for any shape s, we have the ommands
s.moveTo(x,y);
s.move(dx,dy);
where the former moves the shape to oordinates (x,y) on the s reen, and the latter displa es
the shapes by (dx,dy) from its urrent position.
You an hange the size of a shape (ex ept for text) also. Every obje t maintains a s ale
fa tor, whi h is initially set to 1, based on whi h its size is displayed.
s.s ale(relfa tor);
s.setS ale(fa tor);
Here relfa tor, fa tor are expe ted to be double. The rst version multiplies the urrent
s ale fa tor by the spe i ed relfa tor, the se ond version sets the s ale fa tor to fa tor.
You an also de ide whether a shape s is to appear in outline, or it is to be lled with
some olor. For the former, use the ommand
Abhiram Ranade, 2013. Do not distribute 84
s.setFill(v);
where v must evaluate to true or false. This ommand does not apply to Line shapes. The
olor an be spe i ed by writing:
s.setColor( olor);
where olor is spe i ed for example, as COLOR("red"). Note that merely spe ifying "red"
will not work. Instead of red, other standard olor names, e.g. blue, green, yellow, white,
bla k an be used. Use all lower ase letters. Alternatively, you may spe ify the olor by
giving intensities of 3 primary olors, red, green, blue respe tively, by writing COLOR(redVal,
greenVal, blueVal). The 3 values should be numbers between 0 and 255. As you may
guess, red and blue together give purple, while red and green give yellow.
You may hide or unhide a shape s using the ommands
s.hide();
s.show();
respe tively.
5.4.1 Rotation in radians
The left, right ommands of Chapter 1 required angles to be supplied in degrees. How-
ever, most programming languages in luding C++ prefer angles to be represented in radians.
For this a rotate ommand is provided. Thus if s is a shape you may write s.rotate(angle)
where angle must be the angle in radians, measured lo kwise.
5.4.2 Tra king a shape
As the program exe utes, you may move shapes or rotate them or s ale them. You an of
ourse keep tra k of the position, orientation, s ale fa tor yourself, but you do not need to;
simple pp does it for you. The following ommands will return the x oordinate, the y
oordinate, the orientation, and the s ale fa tor respe tively.
s.getX()
s.getY()
s.getOrientation()
s.getS ale()
You may print the values by writing out << s.getOrientation(); and so on, or you may
use them in omputation. The getOrientation ommand will return the angle made by
the shape with the positive x axis, measured lo kwise.
5.4.3 Imprinting on the anvas
Suppose s is a shape. Then the following ommand auses an image of the shape to be
printed on the anvas, at the urrent position of s.
s.imprint();
Abhiram Ranade, 2013. Do not distribute 85
After this, the shape might move away, but the image stays permanently. You an print as
many images of a single shape as you desire. The new image overwrites older images, if any.
The ommand works with all shapes s.
If you merely want to draw lines on the s reen for some reason (e.g. Se tion 18.3) an
additional ommand is also provided.
imprintLine(x1,y1,x2,y2, olor)
or
imprintLine(x1,y1,x2,y2)
This will draw a line between the points (x1,y1) and (x2,y2), of olour olor. If olor is
not given, then the line will be bla k. You ould have got the same e e t by reating a line
and then alling imprint on it; however, the ommand imprintLine is mu h faster. The
speed is sometimes important, as in the appli ation of Se tion 18.3.
5.4.4 Resetting a shape
For ea h shape ex ept Turtle, an reset ommand is provided. This ommand takes the
same arguments as required for reation, and re reates the shape using the new values. For
example, you ould have
Cir le (100,100,15);
wait(1);
.reset(100,100,20);
This would have the e e t of expanding the ir le.

5.5 Cli king on the anvas


The ommand getCli k() an be used to wait for the user to li k on the anvas. It auses
the program to wait until the user li ks. Suppose the user li ks at a point (x; y) on the
s reen. Then the value v = 65536  x + y is returned by the ommand. Note that the li k
is onsidered to be happening on some pixel, i.e. the oordinates x; y of the li k position
are integers. The value returned by getCli k() is also of type int.
Note that standard omputer s reens will have at most a few thousand pixels along the
height and along the width. Thus the li k oordinates x; y will at most be a few thousand.
Thus x; y < 65536. So if you are given v = 65536  x + y, then you an re over x; y by noting
that
x = bv=65536 ; y = v mod 65536
As an example, the following program waits for the user to li k, and then prints out the
oordinates of the point at whi h the user li ked.
main_program{
int li kPos;
Abhiram Ranade, 2013. Do not distribute 86
initCanvas();

li kPos = getCli k();

out << "Cli k position: ("


<< li kPos/65536 <<", " // integer division: trun ates.
<< li kPos % 65536 <<")\n";
}

By the way, 65536 = 2 ; so when you ompute v = 65536  x + y, you are e e tively pla ing
16

the x oordinate in the most signi ant 16 bits of v and y in the least signi ant 16.

5.6 Proje tile Motion


We will now write a program that simulates the motion of a proje tile. Suppose that the
proje tile has initial velo ity 1 pixel per step in the x dire tion, and -5 pixels per step in the
y dire tion (note that the y oordinate grows downward, so this is upward velo ity). Let
us arbitrarily x the gravitational a eleration to be 0.1 pixels/step . For simpli ity assume
2

that the velo ity only hanges at the end of ea h step: at the end of ea h step 0.1 gets added
to the y omponent velo ity.
#in lude <simple pp>

main_program{
initCanvas("Proje tile motion", 500,500);

int start = getCli k();

Cir le proje tile(start /65536, start % 65536, 5);


proje tile.penDown();

double vx=1,vy=-5, gravity=0.1;

repeat(100){
proje tile.move(vx,vy);
vy += gravity;
wait(0.1);
}
wait(10);
}

The program waits for the user to li k. It then pla es a proje tile, a Cir le at the li k
position. Then it moves the proje tile as per its velo ity. The pen of the proje tile is put
down so that the path tra ed by it is also seen. The proje tile is moved for 100 steps.
Abhiram Ranade, 2013. Do not distribute 87
5.7 Best t straight line
Suppose you are given a set of points (x ; y ); (x ; y ); : : : ; (xn; yn). Your goal is to nd a line
1 1 2 2
y = mx + whi h is the losest to these points. We will see a way to do this assuming a
spe i de nition of \ losest".
A natural de nition of the distan e from a point to a line is the perpendi ular distan e.
Instead, we will onsider the \verti al" distan e yi mxi . We will try to minimize the
total distan e of all points from our line; a tually, sin e the quantity yi mxi an be
positive or negative, we will instead minimize the sum of the squares of these quantities, i.e.
n
X
min (yi mxi )2
i=1

Basi ally we have to sele t m; su h that the above quantity is minimized. At the hosen
value of m, the above sum must be smallest, i.e. the derivative of the sum must be 0.
n n
 X X
0 = m (yi mxi )2 = 2 xi (yi mxi )
i=1 i=1

The terms of this an be rearranged as an equation in m and :


X X X
xi + xi = 2
xi yi (5.1)
i i i

We an get another equation by asserting that the quantity to be minimized be ome as small
as possible for the hosen value of , or at that value the derivative must be ome 0:
n n
 X X
0= (y
 i=1 i
mxi ) 2
= 2 (yi mxi )
i=1

This an also be rewritten as an equation.


X X
m xi + n = yi (5.2)
i i
P
De ne p = i xi , q = i xi, r = i xi yi, and s = Pi yi. Then Equation 5.1 be omes
2
P P

pm + q = r and Equation 5.2 be omes qm + n = s. These equations are easily solved


symboli ally, giving
nr qs ps qr
m= =
np q np q 2 2

The program is given below. The variable names in it are as per the dis ussion above.
main_program{ // Fit line to set of points li ked by the user.
out << "Number of points: ";
int n; in >> n; // number of points to whi h the line is to be fit.

initCanvas("Fitting a line to data",500,500);


Abhiram Ranade, 2013. Do not distribute 88
double p=0, q=0, r=0, s=0;
Cir le pt(0,0,0); // Will be used to show point li ked by user
repeat(n){
int Pos = getCli k();
double x = Pos/65536;
double y = Pos % 65536;
pt.reset(x,y,5); // Centered at the li k position
pt.imprint(); // Be ause we will move pt for subsequent points.

p += x*x;
q += x;
r += x*y;
s += y;
}
double m = (n*r - q*s)/(n*p - q*q);
double = (p*s - q*r)/(n*p - q*q);
Line l(0, , 500, 500*m+ );
wait(10);
}

5.8 Con luding Remarks


If it appears to you that de ning shapes is like de ning variables, you would be right! Indeed,
statement su h as:
Cir le 1(100,100,10), 2(300,200,15);
does indeed de ne two variables, 1 and 2. The ommands dis ussed above are invoked on
these variables, and as a result they ause the images on the s reen to be hanged. But from
the view of the C++ ompiler, 1, 2 are in fa t variables.
Just as ordinary variables an be de ned inside repeat loops, so an these shapes. But
just as ordinary variables will get destroyed on e we get to the end of the parent blo k, so
will these shapes.
Further, the names of the shapes, Cir le, Re tangle, Line, Turtle in fa t are the
data types of the orresponding variables. These are spe ial data types reated for simple pp.
C++ allows reation of data types su h as these. We will study this in Chapter 15. For
now, you an just use them.

5.9 Exer ises


1. Draw an 8  8 hessboard having red and blue squares. Hint: Use the imprint om-
mand. Use the repeat statement properly so that your program is ompa t.
2. Plot the graph of y = sin(x) for x ranging in the interval 0 to 4. Draw the axes and
mark the axes at appropriate points, e.g. multiples of =2 for the x axis, and multiples
of 0.25 for the y axis.
Abhiram Ranade, 2013. Do not distribute 89
3. Modify the proje tile motion program so that the velo ity is given by a se ond li k.
The proje tile should start from the rst li k, and its initial velo ity should be in the
dire tion of the se ond li k (relative to the rst). Also the velo ity should be taken
to be proportional to the distan e between the two li ks.
4. Another idea is to treat the se ond li k to be the highest point rea hed by the proje tile
as it moves. For this you may note that if ux; uy are the initial velo ities of the
proje tile in the x; y dire tions, and g the gravitational a eleration, then maximum
height rea hed is ugy . The horizontal distan e overed by the time the maximum height
2

is rea hed is uxguy .


2

5. Modify the proje tile motion program to tra e the traje tories of the proje tile for the
same initial velo ity and di erent angles. As you may know, for a xed velo ity, the
proje tile goes farthest if it is laun hed at 45 degrees to the horizontal. You should be
able to verify this statement using your program.
6. Write a program to produ e the following e e t. First a square appears on the s reen.
Then a tiny ir le appears at the enter. Slowly, the ir le grows until it tou hes the
sides of the square. Then both the ir le and the square start shrinking until they
vanish.
7. Suppose you are given some observed positions of a proje tile. Ea h position is an
(x; y) pair. You are further told that the proje tile is surely known to pass through
the origin (0,0). Derive the best t traje tory for the given points, su h that it passes
through (0,0). For this you will have to adapt the pro ess we followed to t a straight
line.
8. Write a program that a epts 3 points on the anvas (given by li king) and then draws
a ir le through those 3 points.
9. Write a program that a epts 3 points, say p; q; r. Then the program draws the line
joining p; q. Then the line is rotated around the point r, slowly, through one full
rotation. The key question here is how to rotate a line through a point whi h is not
its enter. This an be done in two ways. You ould al ulate the next position of the
line, and then reset the line to that position. Alternatively, you an observe that a
rotation about an external point su h as r an be expressed as a rotation about the
enter and a translation, i.e. a move. This will require you to al ulate the amount of
translation.
10. In this problem you are to determine how light re e ts o a perfe tly re e ting spheri al
surfa e. Suppose the sphere has radius r and is entered at some point (x; y). Suppose
there is a light sour e at a point (x0 ; y). Rays will emerge from the sour e and boun e
o the sphere. As you may know, the re e ted ray will make an angle to the radius at
the point of onta t equal to that made by the in ident ray. Write a program whi h
tra es many su h rays. It should take r; x; y; x0 as input. Of ourse, in the plane the
sphere will appear as a ir le.
Abhiram Ranade, 2013. Do not distribute 90
11. This is an extension to the previous problem. Extend the re e ted rays ba kward till
they meet the line joining the ir le enter and light sour e. The points where the rays
meet this line an be said to be the image of the light sour e in the mirror; as you will
see this will not be a single point, but the image will be di used. This is the so alled
spheri al aberration in a ir ular mirror.
Chapter 6

Conditional Exe ution

Suppose we want to al ulate the in ome tax for an individual. The a tual rules of in ome
tax al ulation are quite omplex. Let us onsider very simpli ed rules as follows:
For males, there is no tax if your in ome is at most Rs. 1,80,000. If your
in ome is between Rs. 180,000 and Rs. 500,000 then you pay 10% of the amount
by whi h your in ome ex eeds Rs. 180,000. If your in ome is between Rs. 500,000
and Rs. 800,000, then you pay Rs. 32,000 plus 20% of the amount by whi h your
in ome ex eeds Rs. 500,000. If your in ome ex eeds Rs. 800,000, then you pay
Rs. 92,000 plus 30% of the amount by whi h your in ome ex eeds Rs. 800,000.
In the programs that we have written so far, ea h statement was exe uted on e, or ea h
statement was exe uted a ertain number of times, as a part of a repeat blo k. The state-
ments that we have learned do not allow us to express something like \If some ondition
holds, then exe ute a ertain statement, otherwise exe ute some other statement.". This
onditional exe ution is required for the tax al ulation above.
The main statement whi h expresses onditional exe ution is the if statement. We will
also dis uss the swit h statement, whi h is sometimes more onvenient. We also dis uss
logi al data, and how it an be stored in the bool type.

6.1 The If statement


We rst give the program whi h al ulates the tax, and then explain ea h statement.
main_program{
float in ome; // in rupees.
float tax; // in rupees.

out << "What is your in ome in rupees? ";


in >> in ome;

if(in ome <= 180000) tax = 0; // first if statement


if((in ome > 180000) && (in ome <= 500000)) // se ond if statement
tax = (in ome - 180000)* 0.1;

91
Abhiram Ranade, 2013. Do not distribute 92
Previous Statement

True
Condition

Consequent
False

Next Statement

Figure 6.1: Flow hart for simple if statement

if((in ome > 500000) && (in ome <= 800000)) // third if statement
tax = 32000+(in ome - 500000)* 0.2;
if(in ome > 800000) // fourth if statement
tax = 92000+(in ome - 800000)* 0.3;

out << "Tax is: " << tax << endl;


}
This program uses the simple form of the if statement, whi h is as follows.
if ( ondition) onsequent
In this the ondition must be an expression whi h evaluates to true or false. We will
soon des ribe how su h expressions an be written. In any ase, the exe ution of the if
statement begins with the evaluation of the ondition expression. If it evaluates to true,
then the onsequent, whi h an be any C++ statement, is exe uted. If the ondition
evaluates to false, then the onsequent is ignored. At this point the exe ution of the if
statement ends, and ontrol passes to the next statement in the program. Pi torially, this
is often shown in the form of a ow hart, Figure 6.1. In this gure, boxes are used to hold
statements to be exe uted, or a tions to be performed. It is ustomary to write onditions
inside diamonds. Lines join the boxes and diamonds showing how ontrol an ow. As you
an see, after evaluating the ondition, either the true bran h is taken, in whi h ase the
onsequent is exe uted, or the false bran h is taken in whi h ase the ontrol dire tly goes
to the next statement.
The simplest form of ondition is as follows.
exp1 relop exp2
where exp1 and exp2 are numeri al expressions, and relop is a relational operator, e.g.
<,>,<=,>=,==,!= whi h respe tively stand for less than, greater than, less than or equal,
greater than or equal, equal, and not equal. Thus in the rst if statement in the program,
in ome <= 180000 is a ondition. If during exe ution, the value of the variable in ome is
at most 180000, then the ondition evaluates to true, and the ondition is said to su eed.
If so the onsequent is exe uted. Thus tax is set to 0. If in ome is greater than 180000,
Abhiram Ranade, 2013. Do not distribute 93
the ondition evaluates to false, and is said to fail. In this ase the onsequent is not
exe uted, i.e. tax remains un hanged. Similarly, in the last if statement, the ondition
is in ome > 800000. The onsequent here, tax = 92000 + (in ome - 800000) * 0.3 is
exe uted if and only if the value of in ome is greater than 800000.
It is possible to spe ify a more omplex ondition in the if statement. For example,
you may wish to perform a ertain operation only if some two onditions are both true. In
other words, you want ondition1 to be true and ondition2 to be true. Thus our ondition
an be a onjun tion (and) of two or more onditions. This is written as follows.
ondition1 && ondition2 && ... && onditionn
The hara ters && should be read as \and". In our se ond if statement, we have an example
1

of this. Here, the ompound ondition is true only if both the sub onditions, in ome >
180000 and in ome <= 500000 are true. In other words, the ompound ondition is true
only if the in ome is between 180000 (ex lusive) and 500000 (in lusive). Only in this ase
is the tax set to (in ome - 180000)* 0.1, i.e. 10% of the amount by whi h the in ome
ex eeds 180000.
Note that we an have a ompound ondition whi h holds if at least one of some set
of onditions holds. Su h a ondition is said to be a disjun tion of (sub) onditions and is
expressed as:
ondition1 || ondition2 || ... || onditionn
The hara ters ||, onstitute the logi al or operator, i.e. the ompound ondition is true
if ondition1 is true or ondition2 is true and so on. Finally, one ondition an be the
negation of another ondition, written as follows:
! ondition
where the ondition ! ondition is said to be the negation of ondition. The ondition
! ondition is true if ondition is itself false, and ! ondition is false if ondition is true.
We note that the se ond if statement an also be written as:
if(!((in ome <= 180000) || (in ome > 500000)))
tax = (in ome - 180000)* 0.1;
Noti e that (in ome <= 180000) || (in ome > 500000) is true if in ome is either less
than or equal to 180000 or greater than 500000, i.e. if the in ome is not in the range 180000
(ex lusive) and 500000 (in lusive). But the ! at the beginning negates this ondition, so
the entire ondition is true only if the in ome is indeed in the range 180000 (in lusive and
500000 (ex lusive). But this is the same ondition as tested in the se ond if statement in
the program!
It is important to learly understand how the above program is exe uted. The exe ution
is as usual, top to bottom. After printing out a message and reading the value of in ome,
the program exe utes the rst if statement. For this the ondition in it is he ked, and
then the onsequent is exe uted if the ondition is true. After this the se ond if statement
is exe uted. So every if statement will be exe uted; the onditions have been so designed
1 The single hara ter & is also an operator, but it means something di erent, see Appendix E.
Abhiram Ranade, 2013. Do not distribute 94

Read income

True
income <= 180000

Tax = 0;
False

income > 180000 True


&&
income <= 500000

tax = (income − 180000)


False * 0.1;

income > 500000 True


&&
income <= 800000
tax = 32000 +
(income − 500000)*0.2;
False

True
income > 800000

tax = 92000 +
(income −800000)*0.3;
False

Print tax

Figure 6.2: Flow hart for the rst in ome tax program
Abhiram Ranade, 2013. Do not distribute 95
so that the ondition in only one if statements will evaluate to true, and hen e only one
onsequent statement will be exe uted. Perhaps the way in whi h ontrol ows is more
obvious in the ow hart of the entire program, shown in Figure 6.2. Note that on e we
dis over a ertain ondition to be true, e.g. that the in ome is at most 180000, we know that
the other onditions annot be true. So the natural question arises: why should we even
he k them?
The more general if statement, dis ussed in the next se tion, allows you to prevent su h
unne essary he ks. But before dis ussing that, we dis uss the notion of blo ks.

6.2 Blo ks
In the if statement dis ussed above, the onsequent was expe ted to be a single statement.
In general, we might want to exe ute several statements if a ertain ondition held, not just
one. The blo k onstru t helps us in this ase.
As dis ussed earlier, a blo k is simply a olle tion of statements that are grouped together
in bra es, f and g. By putting statements into a blo k, we are making a single ompound
statement out of them. A blo k an be pla ed wherever a single C++ statement is required,
e.g. as the onsequent part of the if statement. Suppose for example, we want to print a
message \This person is in the highest tax bra ket." if the in ome is more than 8 lakhs, as
well as al ulate the tax, we would repla e the fourth if statement in the program with the
following.
if (in ome > 800000){
tax = 92000+(in ome - 800000)* 0.3;
out << "This person is in the highest tax bra ket." << endl;
}

You have already used a blo k as a part of the repeat statement. Let us now note that the
general form of the repeat statement is:
repeat ( ount) a tion
where a tion is any statement in luding a blo k. Thus we may write
repeat (10) out << "Test." << endl;

whi h will ause the message "Test." to be printed 10 times.

6.3 Other forms of the if statement


The if-else statement has the following form.
if ( ondition) onsequent
else alternate
Abhiram Ranade, 2013. Do not distribute 96
Previous Statement

False True
Condition

Alternate Consequent

Next Statement

Figure 6.3: If statement with else lause

This statement also begins with the evaluation of ondition. If it is true, then as before
onsequent is exe uted. If the ondition is false, however, then the alternate statement
is exe uted. So exa tly one out of the statements onsequent and alternate is exe uted,
depending upon whether the ondition is true or false. This is shown pi torially in the
ow hart of Figure 6.3.
The most omplex form of the if statement is as follows.
if ( ondition1) onsequent1
else if ( ondition2) onsequent2
else if ( ondition3) onsequent3
...
else if ( onditionn) onsequentn
else alternate
This statement is exe uted as follows. First, ondition1 is he ked. If it is true, then
onsequent1 is exe uted, and that ompletes the exe ution of the statement. If ondition1
is false, then ondition2 is he ked. If it is true, then onsequent2 is exe uted, and that
ompletes the exe ution of the statement. In general, ondition1, ondition2, ... are
exe uted in order, until some onditioni is found to be true. If so, then onsequenti
is exe uted, and the exe ution of the statement ends. If no ondition is found true, then
the alternate is exe uted. It is a eptable to omit the last line, i.e. else alternate. If
the last line is omitted, then nothing is exe uted if none of the onditions are found true.
Figure 6.4 shows a ow hart, for 3 onditions.
Now we an rewrite our tax al ulation program as follows.
main_program{
float in ome, tax;

out << "What is your in ome? ";


in >> in ome;

if(in ome <= 180000) tax = 0; // new first if


else if(in ome <= 500000) // new se ond if
Abhiram Ranade, 2013. Do not distribute 97
Previous Statement

False True
Condition 1

Consequent 1
False True
Condition 2

Consequent 2
False True
Condition3

Alternate Consequent 3

Next Statement

Figure 6.4: Most general if, with 3 onditions

tax = (in ome - 180000)* 0.1;


else if(in ome <= 800000) // new third if
tax = 32000+(in ome - 500000)* 0.2;
else
tax = 92000+(in ome - 800000)* 0.3;

out << "Tax is: " << tax << endl;


}

Noti e that this program ontains only 3 onditions, rather than 4 as in the previous program.
This is be ause if all the 3 onditions are false, we know that the in ome must be bigger
than 800000. Thus even without he king this ondition we an dire tly set the tax to
92000+(in ome - 800000)* 0.3.
Also note that the se ond and third onditions are mu h simpler! In the rst program,
we he ked if the in ome was larger than 180000 and at most 500000. In the new program,
we know that the \new se ond if" is exe uted only if the ondition of \new rst if" failed,
i.e. if the in ome was greater than 180000. But then, we dont need to he k this again in
the \new se ond if". So it suÆ es to just he k if in ome is at most 50000. The third if
statement also simpli es similarly.
Further note that the original program would he k ea h of its 4 onditions no matter
whi h one is true, whereas in this program as soon as the rst true ondition is found,
the orresponding onsequent a tion is performed, and the subsequent onditions are not
he ked. Thus the new program is more eÆ ient than the previous program. Figure 6.5
shows the ow hart for the new program. By omparing to Figure 6.2, perhaps it is easier
Abhiram Ranade, 2013. Do not distribute 98
Read income

False True
income <= 180000

tax = 0;
False True
income <= 500000

tax = (income −180000)


* 0.1;
False True
income <= 800000

tax = 92000 + tax = 32000 +


(income − 800000)*0.3; (income − 32000)*0.2;

print tax

Figure 6.5: Flow hart for se ond in ome tax program

to appre iate how mu h di erent the new program is.

6.4 A di erent turtle ontroller


The turtle driving programs we saw in hapter 1 required us to put information about the
gure we wanted to draw right into program, i.e., the exa t sequen e of forward and turn
ommands that we want to exe ute had to be written out in the program. We will now write
a program whi h will allow the user to ontrol the turtle during during exe ution.
Let us de ide that the user must type the hara ter 'f' to make the turtle go forward by
100 pixels, the hara ter 'r' to make the turtle turn right by 90 degrees, and the hara ter 'l'
to make the turtle turn left by 90 degrees. Our program must re eive these hara ters that
the user types, and then move the turtle a ordingly. Here it is.
main_program{
har ommand;
turtleSim();

repeat(100){
in >> ommand;
if ( ommand == 'f') forward(100);
else if ( ommand == 'r') right(90);
else if ( ommand == 'l') left(90);
else out << "Not a proper ommand, " << ommand << endl;
Abhiram Ranade, 2013. Do not distribute 99
}
}

Remember that har data is really numeri al, so it is perfe tly a eptable to ompare it
using the operator ==. This program will exe ute 100 user ommands to move the turtle
before stopping. Try it!
6.4.1 \Buttons" on the anvas
We an build \buttons" on the anvas using the Re tangle shapes of Se tion 5.3. We an
ontrol the turtle by li king on the buttons. This gives yet another turtle ontroller.
main_program{
initCanvas();

onst float bFx=150,bFy=100, bLx=400,bLy=100, bWidth=150,bHeight=50;


Re tangle buttonF(bFx,bFy,bWidth,bHeight), buttonL(bLx,bLy,bWidth,bHeight);

Text tF(bFx,bFy,"Forward"), tL(bLx,bLy,"Left Turn");


Turtle t;

repeat(100){
int li kPos = getCli k();
int x = li kPos/65536;
int y = li kPos % 65536;

if(bFx-bWidth/2<= x && x<= bFx+bWidth/2 &&


bFy-bHeight/2 <= y && y <= bFy+bHeight/2) t.forward(100);

if(bLx-bWidth/2<= x && x<= bLx+bWidth/2 &&


bLy-bHeight/2 <= y && y <= bLy+bHeight/2) t.left(10);
}
}
The program begins by drawing the re tangles on the s reen. Noti e that we have not given
the oordinate information of the buttons by writing numbers dire tly, but rst reated the
names bFx,bFy and so on having spe i values and then used these names in the button
reation. Using su h names is onvenient: if you want to adjust the layout of buttons later,
you just need to hange the value of some name. Without names, you would have needed to
make hanges in every pla e the number appeared. In the present ase, if you want to hange
the width of the re tangles, you just need to assign a di erent value to bWidth, instead of
worrying in whi h all pla es the width value needs to be hanged.
Next, text is put in the re tangles. Then we go into a loop. Inside, we wait for the user
to li k. We he k whether the li k is inside either of the two re tangles. This is done in the
two if statements in the loop. Ea h he k has two parts: we must he k if the x oordinate
of the li k is between the left edge of the re tangle and the right edge, i.e. the left edge
Abhiram Ranade, 2013. Do not distribute 100
oordinate must be smaller or equal, and the right edge oordinate must be larger or equal.
And orrespondingly we must he k for the y oordinate as well.
This program will only allow 100 li ks; we see later how to make the loop inde nitely
or stop if some ondition is met.

6.5 The swit h statement


In the turtle ontrol program, there was a single variable, ommand, depending upon whi h
we took di erent a tions. A similar situation arises in many programs. So C++ provides
the swit h statement so that we an express our ode su in tly. The general form of the
swit h statement is:
swit h (expression){
ase onstant1:
group(1) of statements usually ending with ``break;''
ase onstant2:
group(2) of statements usually ending with ``break;''
...
default:
default-group of statements
}
The portion onsisting of default: and the group of statements following that is optional.
The expression expression must be of type int. Further ea h onstati in above is required
to be an integer onstant.
The statement exe utes in the following manner. First the expression is evaluated.
If the value is identi al to onstanti for some i, then we start exe uting group(i) state-
ments. We exe ute group(i) statements, then group(i+1) statements and so on, in luding
default-group statements, unless we en ounter a break; statement. If we en ounter a
break then the exe ution of the swit h is omplete, i.e. we do not exe ute the statements
following the break but dire tly go to the statement in the program following the swit h
statement. If the value of expression is di erent from any of the onstant values men-
tioned, then the default-group of statements is exe uted.
If a ertain group(i) does not end in a break, then the exe ution is said to \fall-through"
to the next group. Fall-throughs are onsidered to be rare.
Using a swit h our turtle ontrol program an be written as follows.
main_program{
har ommand;
turtleSim();

repeat(100){
in >> ommand;
swit h( ommand){
ase 'f': forward(100);
break;
Abhiram Ranade, 2013. Do not distribute 101
ase 'r': right(90);
break;
ase 'l': left(90);
break;
default: out << "Not a proper ommand, " << ommand << endl;
}
}
}

As you an see the new program is ni er to read.


Here is an example whi h has fall-throughs. Suppose we want to print the number of
days in the nth month of the year, taking n as the input. Here is the program.
main_program{
int month;
in >> month;
swit h(month){
ase 1: // January
ase 3: // Mar h
ase 5: // May
ase 7: // July
ase 8: // August
ase 10: // O tober
ase 12: // De ember
out << ``This month has 31 days.\n'';
break;
ase 2: // February
out << ``This month has 28 or 29 days.\n'';
break;
ase 4: // April
ase 6: // June
ase 9: // September
ase 11: // November
out << ``This month has 30 days.\n'';
break;
default: out << ``Invalid input.\n'';
}
}
Suppose the input is 5. Then the exe ution will start after the point labelled ase 5:. It
will fall through the ases 5,7,8,10 to ase 12. In this the number of days will be printed to
be 31, and then a break is en ountered. This will omplete the exe ution of the sele t.
The swit h statement is onsidered somewhat error-prone be ause you may forget to
write break;. So be areful.
Abhiram Ranade, 2013. Do not distribute 102
6.6 Conditional Expressions
C++ has a notion of a onditional expression, having the following form.
ondition ? onsequent-expression : alternate-expression
The evaluation of this pro eeds as follows. First the ondition is evaluated. If it is true,
then the onsequent-expression expression is evaluated, and that is the value of the overall
expression. The alternate-expression is ignored. If on the other hand the ondition
evaluates to false, then the onsequent-expression is ignored, the alternate-expression
is evaluated and the resulting value is the value of the overall expression.
Here are some simple examples.
int marks; in >> marks;
int a tualmarks = (marks > 100) ? 100 : marks;
har grade = (marks >= 35) ? 'p' : 'f';
In this if marks read in were more than 100, then a tualmarks would be apped to 100, else
a tualmarks would be set equal to marks. Further, if the marks are at least 35, then grade
is set to 'p' (pass), otherwise to 'f' (fail).
Conditional expressions an be nested, i.e. the onsequent or alternate expressions an
themselves onditional expressions. This allows us to write a very ompa t but unreadable
tax al ulation program.
main_program{
float in ome; in >> in ome;

out << ( // **
in ome <= 180000 ? 0 :
in ome <= 500000 ? (in ome - 180000) * 0.1 :
in ome <= 800000 ? 32000 + (in ome - 500000) * 0.2 :
92000 + (in ome - 800000) * 0.3
) // **
<< endl;
}
We merely read in the in ome, and then al ulate the tax as an expression and dire tly
print it out without storing it into a variable. In the above the parentheses marked ** are
ne essary. This is be ause the operator << has higher pre eden e than the operator <=, i.e.
by default C++ attempts to exe ute << before <=.
The above program is very ompa t, but not re ommended. Most programmers would
onsider it unreadable. However, the onditional expression without nesting is onsidered to
be a useful onstru t.

6.7 Logi al Data


An important part of the if statement are the onditions. We have already seen that a
ondition is either true or false, i.e. we an asso iate the value true or the value false
Abhiram Ranade, 2013. Do not distribute 103
with ea h ondition. We have also seen that onditions an be ombined in di erent ways.
The resulting ombination will also be true or false. We have also seen that there may be
several equivalent ways of writing the same ondition (as we saw for the se ond if statement
of our rst program). In this sense, onditions are similar to numeri al expressions, numeri al
expressions have a value, numeri al expressions an be ombined to build bigger numeri al
expressions, we an have numeri al expressions that are equivalent. In that ase, why not
treat onditions, as just another kind of data? This turns out to be a very good idea, and an
algebra for manipulating onditions, or what we will hereafter refer to as logi al expressions
was developed by George Boole in 1940. C++ supports the manipulation and storage of
logi al data, and in honour of Boole the data-type for storing logi al data is named bool.
You have already seen this data type in Chapter 3, now we will do more interesting things
with it.
First we note that we an assign values of logi al expressions to bool variables. Consider
the following ode.
float in ome; in >> in ome;
bool lowIn ome, midIn ome, highIn ome;
lowIn ome = (in ome <= 180000);
midIn ome = (in ome > 180000) && (in ome <= 800000);
highIn ome = (in ome > 800000);
Suppose during exe ution the value 200000 is given for in ome. Then after the exe ution
of the subsequent statements, the variables lowIn ome, midIn ome, highIn ome would
respe tively have the values false, true, false.
As you an see, the right hand sides of the above assignment statements are onditions,
and whatever the values these onditions have will been put in the orresponding left hand
side variables.
As another example, let us de ne a bool variable that will be true if a hara ter read
from in happens to be a lower ase hara ter. Note that this will happen if the ASCII
value of the hara ter is at least 'a' and at most 'z'. Thus the ode for this ould be
har in_ h;
bool lowerCase;
in >> in_ h;
lowerCase = (in_ h >= 'a') && (in_ h <= 'z');
We will next onsider a more omplex program whi h determines whether a given number
num is prime or omposite. The ability to store logi al values will be useful in this program.
To understand that program we will need to reason about expressions ontaining logi al
data. So we rst dis uss this.
6.7.1 Reasoning about logi al data
As we dis ussed earlier, the same ondition an be expressed in many ways. It is important
to understand whi h expressions are equivalent.
First, let us make a few simple observations. For any logi al value v, we have that v ||
false has the same value as v. The easiest way to he k this is to try out all possibilities:
Abhiram Ranade, 2013. Do not distribute 104
if v is true, then true || false is learly true. If v is false, then false || false is
learly false. Thus false plays the same role with respe t to || that 0 plays with respe t
to numeri al addition. More formally, false is said to be the identity for ||. Likewise true
&& v has the value v for any v. Or in other words, true is the identity for &&.
Another rule is the so alled distributivity of && over ||. Thus, if x,y,z are boolean
variables (or equivalently, onditions), then (x && y) || z is the same as (x && z) || (y
&& z). In a similar manner, it turns out that || also distributes over &&.
Another important rule is that x || !x is always true, and hen e we an repla e su h
expressions with true. Similarly, x && !x an be repla ed with false.
Finally, an important rule is DeMorgan's Law. This says that !x && !y is the same as
!(x || y). Similarly !x || !y is the same as !(x && y).
Consider rst a ondition su h as in ome <= 180000. In ome being at most 180000 is
the same as it not being bigger than 180000. Hen e we an write this ondition also as
!(in ome > 180000).
While it is ne to be able to intuitively understand that the onditions
(in ome > 180000) && (in ome <= 500000)
and
!((in ome <= 180000) || (in ome > 500000))

are the same, you should also be able to dedu e this given the rules given in this se tion.
6.7.2 Determining whether a number is prime
Determining whether a number is prime is an important problem, for whi h very sophis-
ti ated, very fast algorithms are known. We will only onsider the simplest (and hen e
substantially slower than the fastest known) algorithms in this book.
Here is the most obvious idea. We go by the de nition. A number n is prime if it has no
divisors other than itself and 1. So it should suÆ e to he k whether any number i between 1
and itself (both ex lusive) divides it. If we nd su h an i then we de lare x to be omposite;
otherwise it is prime.
This requires us to generate all numbers between 2 and x 1 (both in lusive this time)
so that we an he k whether they divide x. This is really the sequen e generation pattern
(Se tion 3.4.1) whi h we saw, say in the spiral drawing program of Se tion 3.4. There we
made i take 10 values starting at 1. Now we want i to take the x 2 values from 2 to x 1.
So here is the ode fragment we should use:
i=2;
repeat(x-2){
/*
Here i takes values from 2 to x-1.
*/
i = i + 1;
}
Abhiram Ranade, 2013. Do not distribute 105
In ea h iteration of the loop we an he k whether i divides x. This is really the ondition
(x % i) == 0. We want to know whether any su h ondition su eeds. But this is nothing
but a logi al or, of the onditions that arise in ea h iteration. In other words, this itself is
the a umulator pattern mentioned in Se tion 3.4.1. But we know how to implement that!
We saw how to do it to al ulate the sum in the average omputing program of Se tion 3.4.
We must maintain an a umulator variable whi h we set to the identity for the operator in
question, and we update it in ea h step. Say we name our a umulator variable found (sin e
it will indi ate whether a fa tor is found). Then we initialize it to false, the identity for
the OR operation. Then in ea h step of the loop we merely update found, exa tly as we
updated sum in the average omputation program. So our ode fragment be omes:
i=2;
found = false;
repeat(x-2){
found = found || (x % i) == 0;
i = i+1;
}
At the end of this found will indeed be true if any of the expressions (x % i) == 0 was true,
for any value of i. Thus following this ode we simply print prime/ omposite depending upon
whether found is false/true. And at the beginning we need to read in x et . The omplete
program is as follows.
main_program{ //De ide if x is prime.
int x; in >> x;

int i=2;
bool found = false;
repeat(x-2){
found = found || (x % i) == 0;
i = i+1;
}

if (found) out << x << " is omposite." << endl;


else out << x << " is prime." << endl;
}
This program will be improved in several ways later. On e we nd a fa tor of x, i.e. if in
some iteration x % i == 0 be omes true, we will set found to true, and no matter what we
do later, it annot be ome false. So why even do the remaining iterations? This is indeed
orre t: if we are testing if 102 is prime, we will dis over in the rst iteration itself that 102
is divisible by 2, i.e. 2 is a fa tor and that 102 is omposite. So we should prematurely stop
the loop and not do the remaining iterations. In the next hapter we will see how this an
be done.
Note by the way that e e t of found = found || (x % i) == 0; an also be had by
writing if(x % i == 0) found = true; This doesnt look like a umulation, but has the
same e e t.
Abhiram Ranade, 2013. Do not distribute 106
6.8 Remarks
There is a potential pitfall asso iated with the use of the operators = and ==. In mathemati s,
the operator = is used to denote omparison, and sin e most of us learn mathemati s before
programming, we are likely predisposed to use = to mean omparison even in C++, rather
than ==. This will lead to errors. The situation is more serious than what you might think
at rst glan e. If you write ode su h as
if(p = 25) q = 37;
when you mean if(p == 25) q = 37; the ompiler will not regard it as an error. This is
be ause assignment is also an expression, and in this ase, p = 25, the value is 25. The
ompiler will, on its own, try to onvert this value to a boolean value. For this the rule
of onversion is a bit non-intuitive: any non-zero value be omes true and only 0 be omes
false. Thus in the exe ution of the above statement, the assignment q=37 will always
happen.
Many ompilers an be asked to warn if they en ounter su h statements whi h most
likely are silly mistakes made by the programmer. Indeed the GNU C++ ompiler will
give a warning if it sees su h statements in your program, provided you invoke it using the
option -Wparentheses. And in fa t, s++ whi h you use with simple pp indeed alls the
GNU C++ ompiler with this option, so you will get these warnings already if you ompile
with s++. If you really intended the statement to mean the assignment expression (and did
not mistakenly write = instead of ==), then you an merely put the expression inside a pair
of parentheses and write if((p = 25)) q = 37;. This e e tively de lares your rm intent
that you mean p = 25 to be an assignment expression. Thus in this ase no warning will be
issued even if you use the option -Wparentheses.
Another pitfall on erns nesting of if statements, say if the onsequent of an if is itself
another if statement.
if(a > 0) if(b > 0) = 5; else = 6;
This is treated by the ompiler to mean
if(a > 0) {if(b > 0) = 5; else = 6;}
In other words, the else joins with the innermost if, and the outer if is left without an
else lause. Keeping tra k of su h rules is rather umbersome, so it is best if you insert the
bra es yourself. Of ourse if you meant to asso iate the else with the outer if you ould
have written
if(a > 0) {if(b > 0) = 5;} else = 6;
If you omit the bra es, then the ompiler again will warn you if you have used the -Wparentheses
option. Note that the ompiler will have ompiled your program as per the rules of C++,
even when it issues a warning. However, you should treat ompiler warnings as suggestions
to improve the readability of your ode. Indeed, if you use parentheses or bra es as suggested
above, you make your ode more readable to other programmers as well.
Abhiram Ranade, 2013. Do not distribute 107
6.9 Exer ises
1. Modify the turtle program so that the user an spe ify how many pixels the turtle
should move, and also by what angle to turn. Thus if the user types \f100 r90 f100
r90 f100 r90 f100" it should draw a square.
2. Write a program that reads 3 numbers and prints them in non-de reasing order.
3. Write a program whi h takes as input a number denoting the year, and says whether
the year is a leap year or not a leap year.
4. Write a program that takes as input a number y denoting the year and a number d,
and prints the date whi h is the dth day of the year y. Suppose y is given as 2011 and
d as 62, then your program should print \3/3/2011".
5. Write a program that takes as input 3 numbers a; b; and prints out the roots of the
quadrati equation ax + bx + = 0. Make sure that you handle all possible values of
2

a; b; without running into a division by zero or having to take the square root of a
negative number. Even if the roots are omplex, you should print them out suitably.
6. Suppose we wish to write a program that plays ards. The rst step in su h a program
would be to represent ards using numbers. In a standard de k, there are 52 ards,
13 of ea h suite. There are 4 suites: spades, hearts, diamonds, and lubs. The 13
ards of ea h suit have the denomination 2,3,4,5,6,7,8,9,10,J,Q,K,A, where the last 4
respe tively are short for ja k, queen, king and a e. It is natural to assign the numbers
3,2,1,0 to the suites respe tively. The denominations 2 { 10 are assigned numbers same
as the denomination, whereas the ja k, queen, king, and a e are respe tively assigned
the numbers 11, 12, 13, and 1 respe tively. The number assigned to a ard of suite s
and denomination d is then 13s + d. Thus the lub a e has the smallest denomination,
1, and the spade king the highest, 52. Write a program whi h takes a number and
prints out what ard it is. So given 20, your program should print \7 of diamonds", or
given 51, it should print \queen of spades".
7. Write a program that takes a hara ter as input and prints 1 if it is a vowel and 0
otherwise.
8. Can you write the program to determine if a number is prime without using a bool
variable? Hint: ount how many fa tors the number has.
9. A number is said to be perfe t if it is equal to the sum of all numbers whi h are its
fa tors (ex luding itself). So for example, 6 is perfe t, be ause it is the sum of its
fa tors 1, 2, 3. Write a program whi h determines if a number is perfe t. It should
also print its fa tors.
10. Write a program whi h prints all the prime numbers smaller than n, where n is to be
read from the keyboard.
Abhiram Ranade, 2013. Do not distribute 108
11. Write a program that reads in 3 hara ters. If the three hara ters onsist of two digits
with a '.' between them, then your program should print the square of the de imal
number represented by the hara ters. Otherwise your program should print a message
saying that the input given is invalid.
12. Make an animation of a ball boun ing inside a re tangular box. Assume that the box
is atta hed to the ground, and the ball moves horizontally inside, without fri tion.
Further assume for simpli ity that the ball has an elasti ollision with the walls of
the box, i.e. the velo ity of the ball parallel to the wall does not hange, but the
velo ity perpendi ular to the wall gets negated. Put the pen of the ball down so that
it tra es its path as it moves. You an either read the ball position and velo ity from
the keyboard, or you an take it from li ks on the anvas. Move the ball slowly along
its path so that the animation looks ni e.
13. Modify the animation assuming that the box has mass equal to the ball, and is free
to move in the x dire tion, say it is mounted on fri tionless rails parallel to the x
dire tion. Note that now in ea h ollision the velo ity of the box will also hange. If
the box has velo ity v and the ball has velo ity u parallel to the x axis at the time of
the ollision, then these velo ities will be ex hanged during ollision, i.e. will be ome
u and v respe tively. Show the animation of this system. You may want to start o
the system su h that the total momentum in the x dire tion is zero, thereby ensuring
that the box doesnt move out of the s reen.
14. * In the hardest version of the ball in a box problem the box is sitting on a fri tionless
surfa e, and is free to turn. Now after a ollision, the box will in general start rotating
as well as translating. Assume for simpli ity that the mass of the box is uniformly
distributed along its 4 edges, i.e. the base is massless.
15. A digital ir uit takes as input ele tri al signals representing binary values and pro-
esses them to generate some required values, again represented as ele tri al signals.
As dis ussed in Se tion 2.2, a ommon onvention is to have a high voltage value (e.g.
0.7 volts) represent 1, and a low value (e.g. 0 volts) represent a 0. A digital ir uit is
made out of omponents ustomarily alled gates. An AND gate has two inputs and
one output. The ir uit in an AND gate is su h that the output is 1 (i.e voltage at
least 0.7 volts) if both inputs are 1. If any input is a 0 (i.e. voltage 0 volts or less),
then the output is a 0. Likewise, an OR gate also has 2 inputs and a single output.
The output is a 0 if both inputs are 0, and it is one if even one of the inputs is a 1.
An XOR gate has 2 inputs and one output, and the output is 0 i the inputs are both
the same value. Finally, a NOT gate has one input and one output, and the output is
1 if the input is 0, and 0 if the input is 1.
Figure 6.6 shows the symbols for the NOT gate, the AND gate and the OR gate at
the top, left to right, and a ir uit built using these gates at the bottom.
The inputs to a digital ir uit are drawn on the left side, and the outputs on the right.
The gates are pla ed in between. A gate input must either be onne ted a ir uit input
or to the output of some gate to its left. The gate input takes the same value as the
ir uit input or the output to whi h it is onne ted. In the gure, a; b; are the ir uit
Abhiram Ranade, 2013. Do not distribute 109

d
b

Figure 6.6: Cir uit omponents and a ir uit

inputs. Some gate outputs are designated as ir uit outputs, e.g. outputs p; q. Note
that if two wires in the ir uit ross, then they are not deemed to be onne ted unless
a solid dot is present at the interse tion.
In this exer ise, you are to write a program whi h takes as inputs the values of the
ir uit inputs a; b, and prints out the values of the outputs ; d.
16. Develop a mini drawing program as follows. Your program should have buttons alled
\Line" and \Cir le" whi h a user an li k to draw a line or a ir le. After a user li ks
on \Line", you should take the next two li ks to mean the endpoints of the line, and
so after that a line should be drawn onne ting those points. For now, you will have
to imprint that line on the anvas. Similarly, after li king \Cir le" the next point
should be taken as the enter, and the next point as a point on the ir umferen e. You
an also have buttons for olours, whi h an be used to sele t the olour before li king
on \Line" or \Cir le".
Chapter 7

Loops

Consider the following mark averaging problem:


From the keyboard, read in a sequen e of numbers, ea h denoting the marks
obtained by students in a lass. The marks are known to be in the range 0 to 100.
The number of students is not told expli itly. If any negative number is entered,
it is not to be onsidered the marks of any student, but merely a signal that
all the marks have been entered. Upon reading a negative number, the program
should print the average mark obtained by the students and stop.
Using the statements you have learned so far, there is no ni e way in whi h the above program
an be written. It might seem that the program requires us to do something repeatedly, but
the number of repetitions equals the number of students, and we dont know that before
starting on the repetitions. So we annot use the repeat statement, in whi h the number of
times to repeat must be spe i ed before the exe ution of the statement starts.
In this hapter we will learn the while loop statement whi h will allow us to write the
program des ribed above. We will also learn the for loop statement, whi h is a general-
ized version of the while statement. All the programs you have written earlier using the
repeat statement an be written using while and for instead, and often more learly. The
repeat statement is not really a part of C++, but something we added through the pa k-
age simple pp be ause we didnt want to onfuse you with while and for in the very rst
hapter. But having understood these more omplex statements you will nd no real need
for the repeat statement. So we will dis ontinue its use from the next hapter.

7.1 The while statement


The most ommon form of the while statement is as follows.
while ( ondition) body
where ondition is a boolean expression, and body is a statement, in luding a blo k state-
ment. The while statement exe utes as follows.
1. The ondition is evaluated.

110
Abhiram Ranade, 2013. Do not distribute 111
Previous statement in the program

False
Condition

True

Body

Next statement in the program

Figure 7.1: While statement exe ution

2. If the ondition is false, sometimes des ribed as \if the ondition fails", then the
exe ution of the statement is omplete without doing anything more. Then we move
on to exe ute the statement following the while statement in the program.
3. If the ondition is true, then the body is exe uted.
4. Then we start again from step 1 above.
This is shown as a ow hart in Figure 7.1.
Ea h exe ution of the body is alled an iteration, just as it was for the repeat. Ea h
iteration might hange the values of some of the variables so that eventually ondition will
be ome false. When this happens, it will be dete ted in the subsequent exe ution of step
1, and then step 2 will ause the exe ution of the statement to terminate.
As you an perhaps already see, this statement is useful for our marks averaging problem.
But before we look at that let us take a few simple examples.
First we note that using a while, it is possible to do anything that is possible using a
repeat. To illustrate this, here is a program to print out a table of the ubes of numbers
from 1 to 100. Clearly you an also write this using repeat.
main_program{
int i=1;
Abhiram Ranade, 2013. Do not distribute 112
while(i <= 100){
out << ``The ube of `` << i << `` is `` << i*i*i << endl;
i = i + 1;
}
out << ``Done!'' << endl;
}
The exe ution will start by setting i to 1. Then we he k whether i is smaller than or equal
to 100. Sin e it is, we enter the body. The rst statement in the body auses us to print
\The ube of 1 is 1", be ause i has value 1. Then we in rement i. After that we go ba k to
the top of the statement, and he k the ondition again. Again we dis over that the urrent
value of i, 2, is smaller than or equal to 100. So we print again, this time with i=2, so
what gets printed is \The ube of 2 is 8". We again exe ute the statement i = i + 1;,
ausing i to be ome 3. We then go ba k and repeat everything from the ondition he k.
In this way it ontinues, until i is no longer smaller than or equal to 100. In other words,
we exe ute iterations of the loop until (and in luding) i be omes 100. When i be omes 101,
the ondition i >= 100 fails, and so we go to the statement following the loop. Thus we
print \Done!" and stop. But before this we have exe uted the loop body for all values of i
from 1 to 100. Thus we will have printed the ube of all the numbers from 1 to 100.
7.1.1 Counting the number of digits
We onsider a more interesting problem: read in a non-negative integer from the keyboard
and print the number of digits in it. The number of digits in a number n is simply the
smallest positive integer d su h that 10d > n. So our program ould merely start at d = 1,
and try out su essive values of d until we get to a d su h that 10d > n.
Thus we have to generate the sequen e 10; 10 ; 10 ; : : :; but this is just the sequen e
2 3

generation idiom. We should stop generating the sequen e as soon as we generate a sequen e
element, say 10d whi h is larger than n. In other words, we should not stop while 10d  n.
This is what the following ode does.
main_program{
int n; out << "Type a number: "; in >> n;

int d = 1, ten_power_d=10;
// ten_power_d will always be set to 10 raised to d

while(n >= ten_power_d){ // if loop entered,


// number of digits in n must be > d
d++; // so we try next hoi e for d
ten_power_d *= 10;
}

out << "The number has " << d << " digits." << endl;
}
Abhiram Ranade, 2013. Do not distribute 113
Let us see what happens when we run the program. Say in response to the request to type
in a number, we entered 27. Then we would set d to 1 and ten power d to 10. Then we
would ome to the while loop. We would nd that n, whi h equals 27 is indeed bigger than
or equal to ten power d) whi h equals 10. So we enter the loop. Inside the loop, we add 1
to d so that it be omes 2, and we multiply ten power d by 10, so it be omes 100. We then
go ba k to the beginning of the loop and he k the ondition. This time we would nd that
n whose value is 27 is smaller than ten power d whose values is 100. So we do not enter the
loop but instead go to the statement following the loop. Thus we would print the urrent
value of d, whi h is 2, as the number of digits. This is the orre t answer: the number of
digits in 27 is indeed 2.
7.1.2 Mark averaging
This problem, like many problems you will see later, is what we might all a data streaming
problem. By that we mean that the omputer re eives a stream (sequen e) of values, and
we are expe ted to produ e something when the stream terminates. O asionally, we may
be expe ted to print out a stream of values as well, but in the urrent problem, we have to
only print out their average. A general strategy for ta kling su h problems is to ask yourself:
what information do I need to remember at a point in exe ution when some n values of the
stream have been read? The answer to this often suggests what variables are needed, and
how they should be updated.
For the mark averaging problem, we know what we want at the end: we want to print
out the average. To al ulate the average we need to know the sum of all the values that we
read, and a ount of how many values we read. So at an intermediate point in the program,
when some n values have been read, we should keep tra k of n as well as their sum. We dont
need to remember the individual values that we have read so far! So it would seem that we
should keep a variable sum in whi h we maintain the sum of the values that we have read
till any point in time. We should also maintain a variable ount whi h should ontain the
number of values we read. Both variables should start o 0. We will have a repeated portion
in whi h we read a value, and for this we will have a variable alled nextmark. Using these
it would seem that we need to do the following steps repeatedly.
1. Read a value into nextmark.
2. If nextmark is negative, then we have nished reading, and so we go on to al ulating
and printing the average.
3. If nextmark is non-negative, then we add nextmark to sum, and also in rement ount.
4. We repeat the whole pro ess from step 1.
In this we have not written down the pro ess of al ulating the average et . But that is
simply dividing sum by ount. Figure 7.2(a) shows this as a ow hart.
Can we express this ow hart using the while statement? For this, you would need to
mat h the pattern of the ow harts of Figure 7.1 and Figure 7.2(a). It seems natural to
mat h the ondition in the former with the test nextmark >= 0 in the latter. But there is
an important di eren e in the stru ture of the two ow harts. In Figure 7.1 the ondition
Abhiram Ranade, 2013. Do not distribute 114

Start Start

A A
P cin >> nextmark; cin >> nextmark;

A
P
cin >> nextmark;

False False
C nextmark >= 0 C nextmark >= 0

True True
B B
sum = sum + nextmark; sum = sum + nextmark;
count = count + 1; count = count + 1;

Calculate and print average Calculate and print average

(a) (b)

Figure 7.2: Flow harts for averaging


Abhiram Ranade, 2013. Do not distribute 115
test is the rst statement of ea h iteration, while in Figure 7.2(a), the rst statement is
reading the data, and only the se ond statement is the ondition he k.
The ru ial question then is: an we somehow modify the ow hart of Figure 7.2(a)
so that the exe ution remains the same, but the new ow hart mat hes the pattern of
Figure 7.1? Suppose we de ide to move the box labelled A upwards above the point P where
two bran hes merge. We do not want to hange what happens on ea h bran h that enters P,
so then it simply means that we must pla e a opy of A on both bran hes oming into P. This
gives us the ow hart of Figure 7.2(b). As you an see, the two ow harts are equivalent in
that they will ause the same statements to be exe uted no matter what input is supplied
from the keyboard.
Note now that box B and the left opy of A in Figure 7.2(b) are exe uted su essively,
so we an even merge them into a single box ontaining 3 statements. This new box an
be ome the body of a while statement, and box C the ondition. Thus we an write our
ode as follows.
main_program{
float nextmark, sum=0;
int ount=0;

in >> nextmark; // right opy of box A

while(nextmark >= 0){ // box C


sum = sum + nextmark; // Box B
ount = ount + 1; // Box B

in >> nextmark; // left opy of box A


}

out << "The average is: " << sum/ ount << endl;
}
The above program assumes that there will be at least one true mark, so that ount will not
be zero at the end.
Note the general idea arefully: the natural way of expressing our program ould involve
a test in the middle of the ode we wish to repeat. In su h ases, we an get the test to be
at the top by moving around some ode and also making a opy of it. Soon you will start
doing this automati ally.

7.2 The break statement


C++ allows a break; statement to be used inside the body of a while (both forms). The
break statement auses the exe ution of the ontaining while statement to terminate imme-
diately. If this happens, exe ution is said to have broken out of the loop. Here is a di erent
way of writing our mark averaging program using the break statement:
float nextmark, sum=0;
Abhiram Ranade, 2013. Do not distribute 116
int ount=0;

while(true){
in >> nextmark;
if(nextmark < 0) break;
sum = sum + nextmark;
ount = ount + 1;
}
out << sum/ ount << endl;
The rst point to note here is that ondition is given as true. This means that the
statement will potentially never terminate! However, the statement does terminate be ause
of the break statement in the body. After the nextmark is read, we he k if it is negative
{ if so the statement terminates immediately, and we exit the loop. If the nextmark is non-
negative, we add nextmark to sum and so on. The result of this exe ution will be the same
as before. Note that this is similar to the ow hart of Figure 7.2(a).
Is the new program better than the old one? It is better in one sense: the statement in
>> nextmark; is written only on e. In general it is a good idea to not dupli ate ode. First,
this keeps the program small, but more importantly it prevents possible errors that might
arise later. For example, suppose you later de ide that just as you read mark you also want
to print what was read. If the reading ode is in several pla es, then you might forget to
make the hange in all the pla es. You may also think that the basi repetitive unit of work
in the problem is read-pro ess, rather than pro ess-read, as it appears in the old ode. So
in this sense the new ode is more natural.
The old ode was better in that the ondition for terminating the loop was given up
front, at the top. In the new ode, the reader needs to sear h a little to see why the loop
will not exe ute ad in nitum. This ould be umbersome if the loop body was large. So we
annot unequivo ally say that the new ode is better.
Note nally that in ase of nested loops, the break statement allows us to break out of
only the innermost loop statement in whi h it is ontained.

7.3 The ontinue statement


What if someone typed in a number larger than 100 for nextmark? Sin e we are assuming
that marks are at most 100, we ould perhaps ignore the numbers above 100 as being
erroneous. This is onveniently expressed using the ontinue statement.
When a ontinue statement is en ountered during exe ution, the remaining part of the
loop body is ignored. The ontrol goes to the top of the loop, and he ks the ondition
and begins the next iteration if he k omes out true, and so on.
The main loop in the program an be written as follows using the ontinue statement.
while(true){
in >> nextmark;
if(nextmark > 100){
out << "Larger than 100, ignoring." << endl;
Abhiram Ranade, 2013. Do not distribute 117
ontinue;
}
if(nextmark < 0) break;
sum = sum + nextmark;
ount = ount + 1;
}
If nextmark is bigger than 100, then the message is rst printed, and then the rest of the
loop body is skipped. The next iteration is begun, starting with the ondition he k, whi h
in this ase is always true.
Note nally that in ase of nested loops, the ontinue statement auses exe ution to
skip the rest of the body of the innermost loop statement ontaining it.

7.4 The do while statement


The while statement has a variation in whi h the ondition is tested at the end of the
iteration rather than at the beginning. It is written slightly di erently. The form is:
do body while ( ondition);
This is exe uted as follows.
1. The body is exe uted.
2. The ondition is evaluated. If it evaluates to true, then we begin again from step 1.
If the body evaluates to false then the exe ution of the statement ends.
In other words, in the do-while form, the body is exe uted at least on e. You will observe
that the do-while form above is equivalent to the following ode using only the while:
body
while ( ondition) body
So you may wonder: why do we have this extra form as well? As you an see, the new form
is more ompa t if you dont want the ondition he ked for the rst iteration. Here is a
typi al example.
main_program{
float x;
har response;

do{
out << ``Type the number whose square root you want: ``;
in >> x;
out << ``The square root is: `` << sqrt(x) << endl;

out << ``Type y to repeat: ``;


in >> response;
Abhiram Ranade, 2013. Do not distribute 118
}
while(response == 'y');
}
This will keep printing square roots as long as you want.

7.5 The for statement


Suppose you want to print a table of ubes of the integers from 1 to 100. You would solve
this problem using the following pie e of ode.
int i = 1;
repeat(100){
out << i << `` `` << i*i*i << endl;
i = i + 1;
}
The variable i plays a entral role in this ode. All iterations of the repeat are identi al,
ex ept for the value of i. Further, i hanges from one iteration of the loop to another in a
very uniform manner, in the above ase it is in remented by 1 at the end of ea h iteration.
This general ode pattern: that there is a ertain variable whi h takes a di erent value in
ea h iteration and the value determines how the iteration will exe ute, is very ommon.
Be ause of this, the designers of C++ (and other programming languages) have provided a
me hanism for expressing this pattern very ompa tly. This me hanism is the for statement.
Using the for statement, we an express the above ode as follows.
for(int i=1; i <= 100; i = i + 1)
out << i << ` ` << i*i*i << endl;
This ode is equivalent to the repeat loop above. Exa tly why this is the ase will be ome
apparent when we understand the for statement in its general form:
for(initialization ; ondition ; update) body
In this, initialization and update are required to be expressions, typi ally assignment
expressions. As you might remember, an assignment expression is simply assignments to
a variable without in luding the semi olon, e.g. i = i + 1. Further we may in lude the
de nition along with the assignment e.g. int i = 0. As you might expe t ondition must
be a boolean expression. The last part, body may be any C++ statement, in luding a blo k
statement. In our example above, the body onsisted of the statement out << i << `` ``
<< i*i*i << endl;.
The exe ution of a for statement starts with the exe ution of initialization. Then
ondition is evaluated. If ondition is false, then the statement terminates. If the
ondition is true, the statements in the body are exe uted followed by the update. We
repeat this pro ess again starting from evaluation of ondition. This is shown as a ow hart
in Figure 7.3.
Note that any of the elds initialization, ondition, update or body an be empty.
If the ondition is empty, then it is taken as true.
Abhiram Ranade, 2013. Do not distribute 119

Previous statement in the program

Initialization

False
Condition

True

Body

Update

Next statement in the program

Figure 7.3: For statement exe ution


Abhiram Ranade, 2013. Do not distribute 120
The variable named in initialization and update is ustomarily alled the ontrol
variable of the loop. As you might expe t, initialization assigns an initial value to the
ontrol variable, and the update says how the variable must hange from one iteration to the
next. As you an see, in our ube table example, the update indeed adds 1 to the ontrol
variable.
You probably also see why the statement is alled a for statement. It is be ause we
exe ute the body many times, for di erent values of the ontrol variable.
7.5.1 Variables de ned in initialization
As mentioned above, the initialization an ontain a variable de nition, as in our ube-
table program. This variable is reated during initialization, and is available throughout
the exe ution of the for statement, i.e. during all the iterations. It is destroyed only when
the exe ution of the for statement ends. Thus su h a variable annot referred to outside the
for. If the value of the variable is useful after the for exe ution is over, then the variable
should be de ned before the for statement, and only initialized in initialization.
What if I de ne a variable i in initialization, but an i has already been de ned
earlier? So onsider the following ode.
int i=10;

for(int i=1; i<=100; i = i + 1) out << i*i*i << endl;

out << i << endl;

In this ase, we will have shadowing, as dis ussed in Se tion 3.6.3. In parti ular the i de ned
in the rst statement will be di erent from the one de ned in the for statement, but it will
be the same as the one in the last statement! Thus the for statement will print a table of
ubes as before. The last statement will print 10, be ause the variable i referred to in it is
the variable de ned in statement 1.
7.5.2 Break and ontinue
If a break statement is en ountered during the exe ution of body, then the exe ution of the
for statement nishes. This is exa tly as in the while statement.
If the ontinue statement is en ountered, then the exe ution of the urrent iteration is
terminated, as in the while statement. However, before pro eeding to the next iteration,
the update is exe uted. After that ontrol ontinues with the next iteration, starting with
he king ondition and so on.
7.5.3 Style issue
You may well ask: why should we learn a new statement if it is really not needed? Indeed,
any program that uses a for statement an be rewritten using a while, with a few additional
variables and assignments.
Abhiram Ranade, 2013. Do not distribute 121
The reason on erns style. It is mu h the same as why we speak loudly on ertain
o asions and softly on others: our softness/loudness help the listener understand our intent
in addition to our words. Likewise, when I write a for statement, it is very lear to the
reader that I am using a ertain ommon programming idiom in whi h there is a ontrol
variable whi h is initialized at the beginning and in remented at the end of ea h iteration. If
I use either a while statement or a repeat statement, then the reader does not immediately
see all this.
7.5.4 Determining if a number is prime
In Se tion 6.7.2 we developed a program to determine if a number is prime. We remarked
there that the program an be made more eÆ ient by noting that on e we nd a fa tor for
the given number, we an stop he king for additional fa tors and immediately report that
the number is omposite. We an implement this idea using the for statement as follows.
In the program of Se tion 6.7.2 we he k whether the number x whi h is to be he ked
for primality is divisible by i, where i goes from 2 to x-1. Clearly, i will serve ni ely as a
ontrol variable. Furthermore, on e we dete t that x is divisible by i, we an break out of
the loop.
main_program{
int x; in >> x;

bool found = false;


for(int i=2; i < x; i++){
// x is not divisible by 2...i-1
if(x % i == 0){ found = true; break;}
}

if(found) out << "Composite.\n";


else out << "Prime.\n";
}
Note the omment we have added to the ode. It expresses how our knowledge about whether
x is prime evolves as the program goes through the loop. No matter whi h iteration it is,
whatever value i has, we know that x is not divisible by the numbers in the range 2 through
i-1. Here if i is 2, the range is empty, so our laim is to be onsidered true. Comments
su h as this one are useful to people reading the ode, they help in understanding what is
going on.

7.6 Un ommon ways of using for


Most often, the initialization and update in the for statement ea h onsists of an as-
signment to a single variable. However, there are other possibilities too, as we will see in
this se tion.
Abhiram Ranade, 2013. Do not distribute 122
7.6.1 Comma separated assignments
Here is how we might solve the digit ounting problem of Se tion 7.1.1 using the for state-
ment.
main_program{
int n; in >> n;

int d, ten_power_d;
for(d=1, ten_power_d = 10; ten_power_d <= n; d++, ten_power_d *= 10);

out << "The number has " << d << " digits." << endl;
}
There are two noteworthy features of the for statement in the above ode. First, the
initialization and update both onsist of two assignments separated by a omma. This
is allowed. It turns out in C++ the omma is onsidered to be an operator in su h a ontext,
and it merely joins together two assignments!
The se ond noteworthy aspe t is that the above for statement has no body. This is
a eptable.
The above ode is very ompa t, but might be onsidered tri ky by some. The point of
to note, of ourse, is that omma separated assignments an be used as initialization
and update in a for statement in general.
7.6.2 Input in initialization and update
Here is how we ould write the mark averaging ode using a for statement.
main_program{
float nextmark,sum=0;
float ount=0;

for( in >> nextmark; nextmark >= 0; in >> nextmark){


ount++;
sum += nextmark;
}
out << sum/ ount;
}
We said that initialization and update in a for statement must be expressions; but it
turns out that in >> nextmark is an expression! We will dis uss what value it returns in
Se tion 12.6.3. But right now the value does not on ern us; so you an go ahead and use
su h input expressions in initialization and update.
I suspe t that some programmers will like this way of writing the program. It is a bit
un onventional, however, it does make sense to onsider nextmark to be a ontrol variable
for this program.
Abhiram Ranade, 2013. Do not distribute 123
7.7 The Greatest Common Divisor
We will now dis uss what is one of the most elegant, oldest, and useful algorithms ever: the
algorithm for nding the greatest ommon divisor (GCD) due to Eu lid, around 300 B.C.
As you know, the inputs for this problem are positive integers m; n. We are required to
ompute their GCD, whi h is de ned to be the largest integer that divides m; n both. It an
be written using a single while loop.
The algorithm for this, as taught in primary s hools, is to fa torize both the numbers,
and then the greatest ommon divisor (GCD) is the produ t of the ommon fa tors. Another
possibility is to go with the spe i ation: examine the numbers between 2 and min(m; n),
and nd the largest one that divides both. This will work, but is slower than the primary
s hool method.
Eu lid's algorithm is mu h faster than both these methods. The starting point for it is
a relatively simple observation: if d is a ommon divisor of positive integers m; n then it is
a ommon divisor also of m n; n, assuming m > n. The proof is simple: Sin e d divides
m; n we have m = pd; n = qd, for integers p; q . Thus m n = (p q )d, and hen e d divides
m n also. By a similar argument you an also prove the onverse, i.e. if d is a ommon
divisor of m n; n, then d is a ommon divisor of m; n also.
Thus we have shown that every ommon divisor of m; n is also a ommon divisor of
m n; n, and vi e versa. But then it means that the set of ommon divisors of m; n is
identi al to the set of ommon divisors of m n; n. Thus the greatest in the rst set must
be the greatest in the se ond set, i.e. GCD(m; n) = GCD(m n; n).
The last statement has profound onsequen es. It should be read as saying: if you want
the GCD of m; n, you may instead nd the GCD of m n; n assuming m > n. This ould
be onsidered progress, be ause intuitively, you would think that nding the GCD of smaller
numbers should be easier than nding the GCD of larger numbers.
Let us take an example. Suppose we want to nd the GCD of 3977, 943. Thus we
have GCD(3977; 943) = GCD(3977 943; 943) = GCD(3034; 943). But there is no rea-
son why we should use this idea just on e: we an use it many times. Thus we get
GCD(3034; 943) = GCD(2091; 943) = GCD(1148; 943) = GCD(205; 943). At this point
you might realize that we an subtra t all multiples in one shot, and the result is simply
the remainder when dividing the original number 3977 by 943. Thus we ould more dire tly
have written GCD(3977; 943) = GCD(3977%943; 943) = GCD(205; 943).
Be ause GCD is a symmetri fun tion we an subtra t multiples of m just as well as
n. Thus GCD(205; 943) = GCD(205; 943%205) = GCD(205; 123). This further sim-
pli es: GCD(205; 123) = GCD(205%123; 123) = GCD(82; 123) = GCD(82; 123%82) =
GCD(82; 41). At this point if we try to apply our rule we get 82%41 = 0, i.e. the smaller of
the numbers divides the larger, and so it must be the GCD. Thus we have obtained, overall,
that GCD(3977,943)=41.
We an summarize the ideas above into a simple theorem.
Theorem 1 (Eu lid) Suppose m; n are positive integers. If m%n = 0, then GCD(m; n) =
n. Otherwise GCD(m; n) = GCD(m%n; n).
This is enough to write a program. The program starts by reading the numbers into
variables m,n. Then in ea h iteration, we will use Eu lid's theorem to obtain new values for
Abhiram Ranade, 2013. Do not distribute 124
m,n su h that the GCD of the new values is the same as the GCD of the old values. The new
values will keep on getting smaller, but we know that this annot happen inde nitely. Hen e
there must ome a time when we annot redu e the values of m,n using Eu lid's theorem.
But this an happen only when n divides m, whereupon we an print out n as the GCD.
main_program{ // Compute GCD of m,n, where m > n >0.
int m,n;
out << "Enter the larger number (must be > 0): "; in >> m;
out << "Enter the smaller number (must be > 0): "; in >> n;

while(m % n != 0){
int Remainder = m % n;
m = n;
n = Remainder;
}
out << "The GCD is: " << n << endl;
}

7.8 Corre tness of looping programs


It should be intuitively lear that the programs dis ussed in this hapter are orre t. How-
ever, intuition an be de eptive, and as we have dis ussed earlier, it is better to ross- he k.
In this se tion we dis uss how to argue the orre tness of programs more formally.
In arguing the orre tness of repeat loop based programs we an typi ally state what
progress we expe t will happen in ea h iteration, and this an be expressed in the plan that
we write and prove (Se tion 4.2.2). The argument for proving the orre tness of programs
that use while/for loops is more omplex than the argument for repeat based programs
(Se tion 4.2.2). This is be ause we do not know in general how many times a while/for
loop will exe ute. Thus the argument must also show that the loop eventually terminates.
The proof argument for while/for loops tends to typi ally have a two parts: a loop
invariant, and a potential. We will explain these notions next, and along with the explanation
we will prove the orre tness of the GCD program given above.
7.8.1 Loop Invariant
A loop invariant is an assertion about the values taken by variables in a program that must
be true before and after every iteration of the loop. The term invariant is to be understood
like the onservation prin iples of Physi s, e.g. the total energy of the system is the same
after the experiment as it was before. A loop invariant is similar in spirit to the plan we
dis ussed in Se tion 4.2.2.
We next des ribe the invariants needed to prove the orre tness of our GCD program.
Suppose m ; n are the values given as input for variables m,n. We will prove the following
0 0
invariants.
Invariant 1: (Before and after ea h iteration of the loop) The GCD of m,n
remains un hanged, i.e. equals the GCD of m ; n .
0 0
Abhiram Ranade, 2013. Do not distribute 125
Invariant 2: (Before and after ea h iteration of the loop) we have m > n > 0.
Invariant 2 will also be useful to show that the program terminates and has no errors along
the way. Invariant 1 will show that the orre t answer is produ ed.
Invariants are proved using mathemati al indu tion, as you might expe t. We prove the
se ond invariant rst. When ontrol rea hes the loop, for the rst iteration, the variables
m,n will have values m ; n . We will have m > n > 0 assuming the user followed our
0 0 0 0
instru tions. Thus the base ase for the indu tion is established. So now suppose that at the
beginning of some tth iteration, m>n>0. We will prove that at the end of the tth iteration
if any and hen e at the beginning of the t + 1th iteration, we will ontinue to have m>n>0.
So let us onsider the exe ution of the loop. The loop test omputes m%n. This operation
is valid only if n>0. But we assumed that n>0 at the beginning of the iteration. Hen e the
remainder m%n will be well de ned and omputed properly without the possiblity of division
by 0. If m%n is 0, then the loop body will not be entered; there will not be any t + 1th
iteration, and so there is nothing to prove. So assume that the remainder is positive. In
this ase the loop body is entered. The rst statement in the body sets Remainder to the
remainder. Note now that Remainder must have a smaller value than the divisor, n. The
last two statements of the loop respe tively assign the values of n and Remainder to m and
n. Thus at the end of the loop m will have a larger value than n, as required.
The rst invariant, i.e. the GCD of the new values being the same as the GCD of the
old values, is a dire t onsequen e of Eu lid's theorem. However, we will state the proof
more formally. As before, the proof uses mathemati al indu tion. When ontrol rea hes the
loop for the rst iteration, the variables m,n have values m ; n . Thus the GCD of m,n is
0 0
obviously the same as the GCD of m ; n . So the base ase holds. So onsider what happens
0 0
after t iterations. We exe ute the loop test. The loop test requires us to divide m by n. If
the loop test fails, then there is no t + 1th iteration and hen e nothing to prove. However if
the loop test su eeds, then we enter the loop. In the loop, we assign values to m,n exa tly
as per Eu lid's theorem. Hen e the GCD of m,n is un hanged after the assignment, though
the values of m,n have themselves hanged.
7.8.2 Potential
Intuitively, it should be lear that the values of m,n will keep redu ing and hen e eventually
the loop test must su eed. We now observe it formally. The value of m in the next iteration
is the urrent value of n, whi h is known to be smaller than the urrent value of m. Hen e in
ea h iteration, the value of m de reases by at least 1. But sin e n is guaranteed to be always
positive, we know that m will always be positive, i.e. never drop to 0 or be ome negative.
Hen e, the number of iterations annot be more than the value m typed in by the user at
0
the beginning of the program. Thus the loop must terminate sometime!
The key idea in this argument is the observation that some quantity must de rease by at
least some xed amount, but the nature of the loop body is su h that the quantity annot
de rease below a ertain threshold. This establishes that the number of iterations must be
nite, otherwise the quantity will have de reased below the threshold. In the ase of GCD,
it is onvenient to hoose as potential the value of m. But in other programs, there will be
other hoi es, sometimes reativity will be needed to de ne a suitable potential.
Abhiram Ranade, 2013. Do not distribute 126
This quantity is metaphori ally alled the Potential, inspired by arguments involving the
notion of potential energy in Physi s.
7.8.3 Corre tness
Given appropriate invariants and a suitable potential, the orre tness proof is almost done.
Usually it is only a matter of tying up some loose ends.
When the GCD program terminates, we know from the invariant that GCD of the urrent
values of m,n must be the same as the GCD of m ; n . Sin e the loop test must have failed
0 0
just before termination, we know that Remainder == 0, i.e. m % n == 0. But then the
GCD must be n, whi h is indeed what we print. Thus we have established orre tness.
7.8.4 Additional observations regarding the GCD program
We note that the above argument an be sharpened to get a stronger bound on the number
of iterations needed by the GCD program. Let mi; ni denote the value of m and n respe tively
at the beginning of the ith iteration. Let Ri denote the value of Remainder al ulated in
the ith iteration. Then we know:
1. mi = qni + Ri  ni + Ri, sin e the quotient q when we divide m by n in the ith iteration
must be at least 1.
2. mi = ni, ni = Ri. This follows by onsidering the assignments we make at the end
+1 +1
of the loop.
Thus we have mi  ni + Ri = mi + ni  2mi . Thus we have established that the value
+1 +1 +2
of m drops by a fa tor at least 2 in 2 iterations. Thus the number of iterations is at most
2 log m , where m is the value of m as typed in by the user.
0 0
We will nally note that our program runs orre tly even if the user disregards our
2

instru tions and types in the smaller number rst and larger se ond. This hanges the
invariants and the analysis slightly, and you are asked about this in the Exer ises.
7.8.5 Corre tness of other programs
Other programs, e.g. primality ould also be proved orre t in a similar manner.

7.9 Remarks
Looping is a very important operation in programming. In this hapter we have seen how
various problems an be solved using the while loop as well as the for loop, and earlier
we saw the repeat loop. For while and for, there were further variations depending upon
whether we used break, or repli ated ode. Later on in the book, we will see even further
ways of expressing some of the programs we have seen in this hapter.
As we have indi ated, ea h way of writing loops has some advantages and disadvantages.
One may be more readable or less readable, another may avoid dupli ation of ode, and yet
another may be less eÆ ient be ause it does unne essary work. Another onsideration is
Abhiram Ranade, 2013. Do not distribute 127
naturalness: does a ertain way of writing ode more onsistent with how you might think
about the problem? So the hoi e of how to express a program is in the end a subje tive
hoi e. So you should develop your own taste in this regard.
The while and for loops are tri kier than repeat loops. This is be ause it is possible
to make a programming error and write while/for loops that do not terminate. Hen e we
must be more areful in using these loops as ompared to repeat loops. This omplexity
is re e ted in the manner in whi h we argue the orre tness. You may observe that the
orre tness argument for repeat did not need to have anything like a Potential be ause the
repeat loops are guaranteed to terminate no matter what.
We have remarked earlier that proving programs an be tedious for large programs.
However, we will emphasize that even if you dont do full proofs, you should write down
invariants and potentials for ea h non-trivial program that you write.

Exer ises
1. Write a program that prints a onversion table from Centigrade to Fahrenheit, say
between 0Æ C to 100Æ C. Write using while and also using for.
2. Suppose we are given n points in the plane: (x ; y ); : : : ; (xn; yn). Suppose the points
1 1
are the verti es of a polygon, and are given in the ounter lo kwise dire tion around
the polygon. Write a program using a while loop to al ulate the perimeter of the
polygon. Also do this using a for loop.
3. Write a program that returns the approximate square root of a non-negative integer.
For this exer ise de ne the approximate square root to be the largest integer smaller
than the exa t square root. Your are expe ted to not use the built-in sqrt or pow
ommands, of ourse. Your program is expe ted to do something simple, e.g. he k
integers in order 1; 2; 3; : : : to see if it quali es to be an approximate square root.
4. Suppose some ode ontains some while statements. Show how you an repla e the
while statements by for statements without hanging the output produ ed by the
ode.
5. Add a \Stop" button to the turtle ontroller of Se tion 6.4.1. Modify the program so
that it runs until the user li ks on the stop button. Also there should be no limit on
the number of ommands exe uted by the user (100 in Se tion 6.4.1).
6. Write a program that prints out the digits of a number starting with the least signi ant
digit, going on to the most signi ant. Note that the least signi ant digit of a number
n is simply n % 10.

7. Write a program that takes a number n and prints out a number m whi h has the same
digits as m, but in reverse order.
8. A natural number is said to be a palindrome if the sequen e its digits is the same
whether read left to right or right to left. Write a program to determine if a given
number is a palindrome.
Abhiram Ranade, 2013. Do not distribute 128
9. Write a program that takes as input a natural number x and returns the smallest
palindrome larger than x.
10. Add he ks to the GCD ode to ensure that the numbers typed in by the user are
positive. For ea h input value you should prompt the user until she gives a positive
value.
11. Suppose the user types in the smaller number rst and the larger number se ond, in
response to the requests during the exe ution of the GCD program of Se tion 7.7.
Show that the orre t answer will nevertheless be given. State how the invariants and
the analysis of the number of iterations will hange.
12. Write a program that takes a natural number and prints out its prime fa tors.
13. * Write a program that reads in a sequen e of hara ters, one at a time, and stops
as soon as it has read the ontiguous sequen e of hara ters 'a', 'b', 'r', 'a', ' ', 'a',
'd', 'a', 'b', 'r', 'a', i.e. the string \abra adabra". Hint: After you have read a ertain
number of hara ters, what exa tly do you need to remember? You do you need to
remember the entire pre eding sequen e of hara ters, even the last few hara ters
expli itly. Figure out what is needed, and just remember that in your program.
14. * Let x ; : : : ; xn be a sequen e of integers (possibly negative). For ea h possible sub-
1
sequen e xi ; : : : ; xj onsider its sum Sij . Write a program that reads in the sequen e
in order, with n given at the beginning, and prints out the maximum sum Sij over all
possible subsequen es.
Hint: This is a diÆ ult problem. However, it will yeild to the general strategy: gure
out what set of values V (k) we need to remember having seen the rst k numbers.
When you read the k + 1th number, you must ompute V (k + 1) using the number
read and V (k) whi h you omputed earlier.
Chapter 8

Computing ommon mathemati al


fun tions

In this hapter we will see ways to ompute some ommon mathemati al fun tions, su h as
trigonometri fun tions, square roots, exponentials and logarithms. We will also see how to
ompute the greatest ommon divisor of two numbers using Eu lid's algorithm. This is one
of the oldest interesting algorithm, invented well before omputers were even on eived.
The main statement in all the programs of the hapter will be a looping statement. You
ould onsider this hapter to be an extension of the previous, giving more ways in whi h
loop statements an be used.
Some of the material in this hapter requires somewhat deep mathemati s. We will state
the relevant theorems, and try to explain intuitively why they might be true. The pre ise
proofs are outside the s ope of this book.

8.1 Taylor series


Suppose we wish to ompute f (x) for some fun tion f , su h as say f (x) = sin(x). Suppose
we know how to ompute f (x ) for some xed x . Suppose that the derivative f 0 of f and the
0 0
derivative f 00 of f 0 and so on exist at x , and we an evaluate these. Then if x is reasonably
0
lose to x then f (x) equals the sum of the Taylor series of f at x . The ith term of the
0 0
Taylor series is f i0(x )(x x )i=i!, in whi h f i0 is the fun tion obtained from f by taking
0 0
derivative i times. Thus we have:
f (x) = f (x ) + f 0 (x )(x x ) + f 00 (x )
(x x ) + f 000(x ) (x x ) +   
0
2
0
3

0 0 0 0
2! 0
3!
In the typi al s enario, we only ompute and sum the rst few terms of the series, and that
gives us a good enough estimate of f (x). The general theory of this is dis ussed in standard
mathemati s texts and is outside our s ope. However, you may re ognize the rst two terms
as oming from a tangent approximation of the urve, as shown in Figure 8.1. The value of
f (x) equals (the length of) FD. We approximate this by FC, whi h in turn is FB + BC =
EA + (BC/AB)AB = f (x ) + f 0(x )  (x x ).
0 0 0

129
Abhiram Ranade, 2013. Do not distribute 130

A B

f (x)
E F
x0 x
Figure 8.1: Tangent approximation of f at A, (x ; f (x ))
0 0
Abhiram Ranade, 2013. Do not distribute 131
8.1.1 Sine of an angle
As an example, onsider f (x) = sin(x), where x is in radians. Then hoosing x = 0 we
0
know f (x ) = 0. We know that f 0(x) = os(x), f 00(x) = sin(x), f 000(x) = os(x) and
0
so on. Sin e os(0) = 1, we know the exa t value of every derivative, it is either 0, 1 or -1.
Thus we get
sin(x) = x x3! + x5! x7! + x9!   
3 5 7 9

Here the angle x is in radians. When a series has alternating positive and negative terms,
and the terms get loser and loser to 0 for any xed x, then it turns out that the error in
taking just the rst k terms is at most the k + 1th term (absolute value). The kth term of
our series is ( 1)k x k =(2k 1)!. Thus if we want the error to be  then we should ensure
+1 2 1

x k =(2k + 1)!  .
2 +1

We have already seen how to sum series (Se tion 4). Clearly we will need a loop, in the
kth iteration of whi h we will al ulate the series to k terms. We must terminate the loop
if the last added term is smaller than our target . We an al ulate the kth term tk from
s rat h in the kth iteration, but it is useful to note the following relationship:
 
x2k 1
x2
tk = ( 1) 1)! = tk ( 1) (2k 2)(2k 1)
k +1
(2k 1

provided k > 1. If k = 1 then tk = 1, of ourse, and we dont use the above relationship.
Thus within the loop we only ompute the terms for k = 2; 3; : : : as needed. Thus our ode
be omes:
main_program{
double x; in >> x;

double epsilon = 1.0E-20, sum = x, term = x;

for(int k=2; abs(term) > epsilon; k++){


// Plan: term = t_{k-1}, sum = sum of k-1 terms
term *= -x * x /((2*k-2)*(2*k-1));
sum += term;
}

out << sum << endl;


}
The ommand abs stands for absolute value, and returns the absolute value of its argument.
8.1.2 Natural log
Consider f (x) = ln x, the natural logarithm of x. One way of de ning it is
Z x
ln x = 1 du u
1
Abhiram Ranade, 2013. Do not distribute 132
So from this, we an nd its Taylor series. Clearly f 0(x) = 1=x. f 00(x) = 1=x and so on. 2

It is onvenient to use x = 1. Thus we get:


0

h2 h3 h4
ln1 + h = h 2 + 3 4   
A very important point to note for this series is that the series is valid only for 1 < h  1.
We noted earlier that the Taylor series is valid only if x is lose enough to x , or equivalently 0
x x = h is small. For the ln fun tion, we have a pre ise des ription of what lose enough
0
means: within a unit distan e from x . 0
Even so, note that you an indeedxuse the series to al ulate ln x for arbitrary values of
x. Simply observe that ln x = 1 + ln e . Thus by fa toring out powers of e we will need to
use the series only on a number smaller than 1.
8.1.3 Some general remarks
Note that the Taylor series is often written as
h2 h 3
f (x0 + h) = f (x0 ) + f 0 (x0 )h + f 00 (x0 ) + f 000 (x ) +   
2! 3! 0

If we hoose x = 0, we get the M Laurin series, whi h is


0

x
+ f 000(0) x
2 3
f (x) = f (0) + f 0 (0)x + f 00 (0)
2! 3! +   
In general, the terms of the Taylor series in rease with x. Thus, it is best to keep x
small if possible. For example, suppose we wish to ompute sin(100:0). One possibility is
to use the previous program spe ifying 100.0 as input. A better way is to subtra t as many
multiples of 2 as possible, sin e we know that sin(x + 2n) = sin(x) for any integer n. In
fa t identities su h as sin(x) = sin( x) an be used to further redu e the value used in
the main loop of the program. In fa t, noting that the Taylor series for os(x) is:
os(x) = 1 x2! + x4! x6! +   
2 4 6

we an in fa t ompute the sine using sin(x) = os(=2 x) if =2 x happens to be smaller


in absolute value than x.
The proof of the Taylor series expansion is well beyond the s ope of this book. However,
we have provided some intuitive justi ation for the rst two terms by onsidering the tangent
to approximate the fun tion urve, Figure 8.1. 1

You might be familiar with the formula ( ) = + 12 2, in whi h ( ) is the distan e overed in time
1 s t ut at s t

tby a parti le moving at a onstant a eleration , with initial velo ity . Note that = (0), = (0)
a u u s
0
a s
00

and with this substitution the formula an be written as ( ) = (0) + (0) + (0) t22 , whi h resembles the
s t s s
0
t s
00

Taylor series in the rst 3 terms.


Abhiram Ranade, 2013. Do not distribute 133
8.2 Numeri al integration
We onsider another way of omputing ln x given x. Re all the de nition:
Z x
ln x = 1 du u
1

In other words, ln x is the area under the urve y = 1=u between u = 1 and u = x. So we
an nd ln x if we an nd the area!
Well, we annot ompute the area exa tly, but we an approximate it. In general suppose
we wish to approximate the area under a urve f (u) = 1=u from some p to q. Then we an
get an overestimate to this area by onsidering the area of the smallest axes parallel re tangle
that overs it. The height of this re tangle is f (p) (be ause f is non-in reasing) and the
width is q p. Thus our required approximation (over estimate) is (q p)f (p). This is
the strategy we will use, after dividing the required area into n verti al strips. Sin e the
urve goes from 1 to x the width of ea h strip is w = (x 1)=n. The ith strip extends from
u = 1+ iw to u = 1+(i +1)w, where we will onsider i to be ranging between 0 and n 1 as
is ustomary, rather than between 1 and n. The height of the re tangle overing this strip
is f (1 + iw) and hen e the area is wf (1 + iw). Thus the total area of the re tangles is:
n 1
X
wf (1 + iw) =
n 1
X
w
1
i
=0 i =0
1 + iw
But evaluation of this formula is easily translated into a program! In fa t i will naturally
serve as a ontrol variable for our for loop. We will take ea h su essive term of the series
and add it into a variable area whi h we rst set to 0. The following is the omplete program.
main_program{
float x; in >> x; // will al ulate ln(x)
int n; in >> n; // number of re tangles to use
float w = (x-1)/n; // width of ea h re tangle
float area = 0; // will ontain ln(x) at the end.
for(int i=0; i < n; i++)
area = area + w /(1+i*w);
out << "Natural log, from integral: "<< area << endl;
}
We note that C++ already provides you a single ommand log whi h an be invoked as
log(x) and it returns the value of the natural logarithm. This ommand uses some ode
probably more sophisti ated than what we have written above, and it guarantees that the
answer it returns will be orre t to as many bits as your representation. So we an use the
ommand log to he k how good our answer is. To do this simply add the line
out << "Natural log, from built-in fun tion: "<< log(x) << endl;
before the end of the program given above. This will ause our answer to be printed as well
as the true answer, and so we an ompare.
Abhiram Ranade, 2013. Do not distribute 134
It is worth pointing out that there are two kinds of errors in a omputation su h as the
one above. The rst is the error produ ed by the mathemati al approximation we use to
al ulate a ertain quantity. For the natural log, this orresponds to the error that arises
be ause of approximating the area under the urve by the area of the re tangles. This error
will redu e as we in rease n, the number of re tangles. The se ond kind of error arises
be ause on a omputer numbers are represented only to a xed pre ision. Thus, we will have
error be ause our al ulation of the area of ea h re tangle will itself not be exa t. If we use
float representation then every number is orre t only to a pre ision of about 7 digits. If
you add n numbers ea h ontaining an (additive) error of , then the error in the sum ould
be ome n, assuming all errors were in the same dire tion. Even assuming p that the errors
are random, it is possible to show that the error will be proportional to n. In other words,
if you add 10000 numbers, ea h with an error of about 10 , your total error is likely to have
7

risen to about 10 (if not to 10 ). Thus, we should hoose n large, but not too large. The
5 3

exer ises ask you to experiment to nd a good hoi e. Note that you an redu e the se ond
kind of error by representing the numbers in double rather than float.
Another variation on the method is to approximate the area under the urve by a sequen e
of trapeziums. This indeed helps. This method, and the more intriguing method based on
Simpson's rule are left to the exer ises.

8.3 Bise tion method for nding roots


A root of a fun tion f is a value x su h that f (x ) = 0. In other words, a point where the
0 0
plot of the fun tion tou hes the x axis. Many problems an be expressed as nding the roots
of an equation. For example, suppose we want to nd the square root of 2. Then instead we
ould ask for the rootspof the polynomial f (x) = x 2. Clearly, if f (x) = 0 then we have
2

x 2 = 0, i.e. x =  2 and this would give us the square root of 2. So nding roots is a
2

very important mathemati al problem.


In this se tion, we will see a very simple method for nding roots approximately. The
method will require that (a) we are given values xL  xR su h that f (xL ) and f (xR ) have
opposite signs, (b) f is ontinuous between xL and xR . These are fairly minimal onditions,
for example for f (x ) = x 2 we an hoose xL = 0 giving f (xL) = 2, and xR = 2 (or any
2 2

large enough value), giving f (xR ) = 2. Clearly xL ; xR satisfy the onditions listed above.
Be ause f is ontinuous, and has opposite signs at xL; xR , it must pass through zero
somewhere in the ( losed) interval [xL; xR ℄. We an think of xR xL is the degree of un er-
tainty, (or maximum error) in our knowledge of the root. Getting a better approximation
merely means getting a smaller interval, i.e. xL; xR su h that xR xL is smaller. If the size
of the interval is really small, we an return either endpoint as an approximate root. So the
main question is: an we somehow pi k better xL ; xR given their urrent values.
A simple idea works. Consider the interval midpoint: xM = (xL + xR )=2. We ompute
xM and nd the sign of f (xM ). Suppose the sign of f (xM ) is di erent from the sign of
f (xL ). Then we know an set xR = xM . Clearly the new values xL ; xR satisfy our original
requirements. If the sign of xM is the same as the sign of xL, then it must be di erent from
the sign of xR . In that ase (see Figure 8.2) we set xL = xM . Again the new values of xL; xR
satisfy our 2 onditions. Hen e in ea h ase, we have redu ed the size of the interval, and
thus redu ed our un ertainty. Indeed if we want to redu e our error to less than some , then
Abhiram Ranade, 2013. Do not distribute 135

(xR ; f (xR))

xL xM xR
Root

(xM ; f (xM ))
(xL ; f (xL))
Figure 8.2: Bise tion method. Next we will have xL = xM .
Abhiram Ranade, 2013. Do not distribute 136
we must repeat this pro ess until xR xL be omes smaller than . Then we would know
that they are both at a distan e at most  from the root, sin e the root is inside the interval
[xL ; xR ℄.
The ode is then immediate. We write it below for nding the square root of 2, i.e. for
f (x) = x 2.
2

main_program{ // find root of f(x) = x*x - 2.


float xL=0,xR=2; // invariant: f(xL),f(xR) have different signs.
float xM,epsilon;
in >> epsilon;
bool xL_is_positive, xM_is_positive;
xL_is_positive = (xL*xL - 2) > 0;
// Invariant: xL_is_positive gives the sign of f(x_L).

while(xR-xL >= epsilon){


xM = (xL+xR)/2;
xM_is_positive = (xM*xM -2) > 0;
if(xL_is_positive == xM_is_positive)
xL = xM; // does not upset any invariant!
else
xR = xM; // does not upset any invariant!
}
out << xL << endl;
}

8.4 Newton Raphson Method


We an get a faster method for nding a root of a fun tion f if we have a way of evaluating
f (x) as well as its derivative f 0 (x) for any x. To start o this method, we also need an initial
guess for the root, whi h we will all x . Often, it is not hard to nd an initial guess; indeed
0
in the example we will take, almost any x works as the initial guess.
In general, the Newton-Raphson method takes as input a urrent guess for the root, say
xi . It returns as output a (hopefully) better guess, say xi . We then ompute f (xi ), if it
+1 +1
is lose enough to 0, then we report xi as the root. Otherwise, we repeat the method with
+1
xi to get, hopefully, an even better guess xi .
+1 +2
The pro ess of omputing xi given xi is very intuitive. We know from Se tion 8.1 that
+1
f (x)  f (xi ) + f 0 (xi )  (x xi ), assuming x xi is small. In this equation we ould hoose
x to be any point, in luding the root. So let us hoose x to be the root. Then f (x) = 0.
Thus we have 0  f (xi) + f 0(xi)  (x xi ). Or in other words, x  xi ff0 xxii . Noti e that
( )

the right hand side of this equation an be evaluated. Thus we an get an approximation to
( )

the root! This approximation is what we take as our next andidate.


f (xi )
xi = xi (8.1)
+1
f 0 (xi )
That is all there is! Figure 8.3 shows what happens graphi ally. The point A with oordinates
(xi ; 0) represents our urrent estimate of the root. We draw a verti al line from A up to the
Abhiram Ranade, 2013. Do not distribute 137

B (xi ; f (xi))

Root C A
xi+1 xi
f (x)

Figure 8.3: One step of Newton-Raphson

fun tion taking us to the point B, having oordinates (xi; f (xi)). At B we draw a tangent to
the fun tion f , and the tangent interse ts the x axis in point C . If we onsider the tangent
to be a good approximation to f , then the root must be point C. Indeed, we take the x
oordinate of C to be our next estimate xi . Thus we have
+1

AB f (xi )
xi = xi AC = xi = xi
+1
AB=AC f 0 (xi )
whi h is what we obtained earlier arguing algebrai ally. At least in the gure, you an
see that our new estimate is better, indeed the point C has moved loser to the root as
ompared to the point A. It is possible to argue formally that if xi is reasonably lose to root
to start with, then xi will be even loser. Indeed, in many ases, it an be shown that the
+1
number of bits of xi that are orre t essentially double in going to xi . Thus a very good
+1
approximation to the root is rea hed very qui kly. The proof of all this is not too hard, at
least for spe ial ases, but beyond the s ope of this book.
We now show how the Newton-Raphson method an be used to nd the square root
of any number y. As with the bise tion method, we must express the problem as that of
2

nding the root of an equation: f (x) = x y. We also need the derivative, and this is
2

f 0 (x) = 2x. The update rule, xi = xi ff0 xxii in this ase be omes
+1
(
(
)
)

xi y 1
2
y
xi = xi = (xi + )
+1
2xi 2 xi
The Babylonians used the same method as early as 2000 BC to nd square roots. But they probably
2
did not derive it as a spe ial ase of a general root nding pro edure.
Abhiram Ranade, 2013. Do not distribute 138
Next we need an initial guess. The standard idea is to make an approximate plot of the
fun tion, and hoose a point whi h appears lose to the root. In this ase it turns out that
almost any initial guess is ne, ex ept for 0, be ause at 0 the term y=xi would be unde ned.
So for simpli ity, we hoose x = 1. So we are ready to write the program. The basi idea is
0
to maintain a variable xi representing the urrent guess. We will update xi in ea h iteration
using the above rule, and initialize xi to 1.
main_program{
double xi=1, y; in >> y;
repeat(10){
xi = (xi + y/xi)/2;
}
out << xi << endl;
}

This program will run a xed 10 iterations, and al ulate the estimates x ; x ; : : : ; x , start-
1 2 10
ing with x = 1. But we an also run a number of iterations depending upon how mu h
0
error we wish to tolerate.
This is slightly tri ky. If the a tual root is x , then the error in the urrent estimate
xi is jxi x j. Indeed, if we exa tly knew the error, i.e. the value v = jxi x j, we ould
dire tly ompute the root by noting that x = xi  v. So we need to make an estimate for
the error. A ommon estimate is f (xi). Indeed, f (xi) is the verti al distan e of the point
(xi ; 0) to the urve f whereas the exa t error, xi x is the horizontal distan e of the point
(xi ; 0) to the urve. Indeed, when the verti al distan e be omes 0, so would the horizontal.
So our program an terminate when the error estimate f (xi) = xi y be omes small, i.e.
2

when xi*xi-y be omes smaller than some threshold


main_program{
float y; in >> y;
float xi=1;
while(abs(xi*xi - y) >0.001){
xi = (xi + y/xi)/2;
out << xi << endl;
}
}
In the above ode we have used the built-in fun tion abs whi h returns the absolute value
of its argument.

8.5 Summary
This hapter has introdu ed several new ideas, though no new programming langauge fea-
tures.
Abhiram Ranade, 2013. Do not distribute 139
8.5.1 Mathemati al ideas
We saw some general te hniques for omputing mathemati al fun tions. We saw that if
the fun tion and its derivatives are easy to evaluate for some values of the argument, then
the Taylor series of the fun tion an often be used to give an algorithm that evaluates the
fun tion for all values of the argument.
We also saw that omputation of a fun tion f ould be expressed as the problem of
nding the roots of another fun tion g. Roots an often be found using various methods.
These methods require that we should be able to evaluate g and possibly its derivatives at
arbitrary points.
8.5.2 Programming ideas
The rst idea was that the values required in ea h iteration of the loop need not be al ulated
afresh, they ould be al ulated from values al ulated in the pre eding iterations. We saw
the use of this idea in the al ulation of sin x.
The se ond important idea was that some properties of ertain variables may remain
un hanged over the iterations of a loop. We saw for example that GCD(m; n) remained the
same at the beginning of ea h iteration of the loop in our program. Su h a property that
remains the same at a given point in the loop is ommonly alled a loop invariant. The
notion of an invariant is important in reasoning about programs.
The nal important idea is that of a potential fun tion. We argued that the GCD program
must terminate be ause the value of Large had to de rease in ea h iteration of the loop,
and the value ould never drop below zero. It is ustomary to refer to su h a quantity as a
potential fun tion for the loop. If we an argue that the potential must steadily drop but
annot drop below a ertain limit, then the only way this an happen is if the loop stops
after a nite number of iterations. The name arises from Physi s, where ustomarily the
parti les (or systems) have a tenden y to go from high potential (energy) to low.

Exer ises
1. Write a program to nd ln x for arbitrary x using the Taylor series. Che k your answer
by using the built in log ommand.
2. Write down the Taylor series for f (x) = ex, noting that f i0(x) = ex. It is onvenient
to expand around x = 0, i.e. onsider the Ma Laurin series. This series is valid for
0
all values of x, however, it is a good idea to use it on as small values of x as possible.
Write a program to ompute ex, and he k against the built in ommand exp.
3. Run the program for omputing natural log for various hoi es of n and see how the
result varies. For what value of n do you get an answer losest to the log fun tion of
C++?
4. A more a urate estimate of the area under the urve is to use trapeziums rather than
re tangles. Thus the area under a urve f (u) in the interval [p; q℄ will be approximated
Abhiram Ranade, 2013. Do not distribute 140
by the area of the trapezium with orners (p; 0), (p; f (p)), (q; f (q)), (q; 0). This area
is simply (f (p) + f (q))(q p)=2. Use this to ompute the natural logarithm.
5. Simpson's rule gives the following approximation of the area under the urve of a
fun tion f : Z b    
b a a+b
f (x)dx 
a 6 f (a) + 4f 2 + f (b)
Use this rule for ea h strip to get another way to nd the natural log.
6. Suppose we are given n points in the plane: (x ; y ); : : : ; (xn; yn). Suppose the points
1 1
are the verti es of a polygon, and are given in the ounter lo kwise dire tion around the
polygon. Write a program to al ulate the area of the polygon. Hint 1: Break the area
into small triangles with known oordinates. Then ompute the lengths of the sides of
the triangles, and then use Heron's formula to nd the area of the triangles. Then add
up. Hint 2: Break the boundary of the polygon into two parts, an up fa ing boundary
and a down fa ing boundary. Express the area as the area under these boundaries ea h
onsidered as fun tions f (u).
7. Children often play a guessing game as follows. One hild, Kashinath, pi ks a number
between 1 and 1000 whi h he does not dis lose to another hild, Ashalata. Ashalata
asks questions of the form \Is you number between x and y?" where she an pi k x; y
as she wants. Ashalata's goal is to ask as few questions as possible and determine the
number that Kashinath pi ked. Show that Ashalata an guess the number orre tly
using at most 10 questions. Hint: Use ideas from the bise tion method.
8. Write a program to nd ar sin(x) given x.
9. Consider a ir uit in whi h a voltage sour e of VCC = 1:5 volts is applied to a diode
and a resistan e of R = 1 Ohm onne ted in series, Figure 8.4. The urrent I through
a diode a ross whi h there is a potential drop of V is
I = IS (eV = nVT 1)
( )

where IS is the reverse saturation urrent of the diode, VT is the thermal voltage whi h
is about 25 mV at room temperature (300 Kelvin), and n is the ideality fa tor. Suppose
the diode we are using has n = 1 and IS = 30 mA. Write a program that nds the
urrent. Use your program to also nd the urrent when the voltage sour e is reversed.
10. Consider the problem of nding the roots of f (x) = x x=2+1=4. See what happens
3

using the Newton-Raphson method for guesses for the initial value. In parti ular, try
x = 1 and x = 0:5. Can you solve this using the bise tion method?
0 0
Abhiram Ranade, 2013. Do not distribute 141

Figure 8.4: Diode ir uit


Chapter 9

Fun tions

In the pre eding hapters, we have seen programs to do many things, from drawing polygons
and mis ellaneous pi tures to al ulating in ome tax and nding the greatest ommon divisor
(GCD) and nding roots. It is on eivable that we will want to write more and more omplex
programs in whi h some of these operations, e.g. nding the GCD, is needed at many pla es.
One possibility is to opy the ode for the operation in as many pla es as is required. This
doesnt seem too elegant, and is also error prone. Wouldnt it be ni e, if for ea h frequently
used operation you ould somehow onstru t a \ ommand" that ould then be used wherever
you want in your program? Just as we have a ommand sqrt for omputing the square root,
or ommands for to ompute the trigonometri ratios (Se tion 1.5) an we build a g d
ommand that will ompute the GCD of two numbers when demanded? This an be done,
and how to build su h ommands is the subje t of this hapter.
The term fun tion is used in C++ to denote what we have so far informally alled a
ommand. In some languages the terms pro edure or subprogram are also used. In what
follows, we will use the term fun tion.

9.1 De ning a fun tion


Suppose that we indeed need to frequently ompute the GCD, and so would like to have
a fun tion whi h omputes this. It is natural to hoose the name g d for this fun tion. It
ould take two numbers as arguments, and return their GCD, whi h ould then be used. As
an example, suppose you wanted to nd the GCD of 24 and 36, and also the GCD of 99 and
47. If we had a g d fun tion as des ribed, then we ould write a very simple main program
as follows.
main_program{
int a=36,b=24, =99,d=47;
out << g d(a,b) << endl;
out << g d( ,d) << endl;
}

Sin e we dont already have su h a g d fun tion, we must de ne it. We dis uss how to do
this next.

142
Abhiram Ranade, 2013. Do not distribute 143
int g d // return-type fun tion-name
(int m, int n) // parameter list: (parameter-type parameter-name ...)
{ // beginning of fun tion body
while(m % n != 0){
int Remainder = m % n;
m = n;
n = Remainder;
}
return n;
} // end of fun tion body

Figure 9.1: De nition of a fun tion to ompute the GCD


Basi ally, in the de nition, we must spe ify what needs to happen when the fun tion is
alled during exe ution, e.g. for the all g d(a,b) in the main program above. In essen e, the
idea is to have a small program run, sort of in the ba kground, for omputing the GCD. This
program, whi h we will refer to as a subprogram must be given the inputs, (in the present
ase, the values of the numbers whose GCD is to be omputed), and some me hanism must
be established for getting ba k the result (in the present ase the omputed GCD) of the
omputation to the main program. While the sub-program runs, the main program must
simply wait.
Figure 9.1 shows the ode for de ning g d. The simplest way to use the de nition is to
pla e it in the same le as the main program given earlier, before the main program. If you
ompile and run that le, then it will indeed print 12 and 1, the GCD respe tively of 24,
36 and 99, 47, as you expe t. The requirement that the fun tion de nition be pla ed before
the main program is similar to the requirement that a variable must be de ned before it is
used. We an relax this requirement slightly, as will be seen in Se tion 11.2.7.
In general, a fun tion de nition has the form:
type-of-return-value fun tion-name (parameter1-type parameter1-name,
parameter2-type parameter2-name, ...){
body
}
The de nition begins with type-of-return-value, whi h indi ates the type of the value
returned by the fun tion. In the GCD example, the fun tion omputes and evaluates the
GCD, whi h has type int, so our de nition (Figure 9.1) mentions this.
Next is fun tion-name, the name of the fun tion being de ned. In our example, we hose
to all our fun tion g d, so that is what the ode states. Any valid identi er (Se tion 3.1.1)
an be hosen as a fun tion name.
Next is a parenthesised list of the parameters to the fun tion, together with their types.
In our ase, there are two parameters, m,n both of type int.
Finally, omes the ode, body, that is used to ompute the return value. The body is
expe ted to be a sequen e of statements, just as you would expe t in any main program. It
an ontain de larations of variables, onditional statements, looping statements, everything
Abhiram Ranade, 2013. Do not distribute 144
that an be present in a main program. However, there are two additional features. The
ode in the body an refer to the parameters, as if they are variables. Further, the the body
must ontain a return statement, whi h we explain shortly. We note that the body of the
de nition in Figure 9.1 is taken substantially from the program developed in Se tion 7.7.
9.1.1 Exe ution: all by value
Consider our g d fun tion and main program. While exe uting the main program, suppose
that ontrol arrives at the all g d(a,b). We des ribe the general rule that determines what
happens, and also mention what happens in our spe i ase.
1. The arguments to the all are evaluated. In our ase it simply means fet hing the
values of the variables a,b, viz. 36,24. But in general, the arguments ould be arbitrary
expressions whi h would have to be evaluated.
2. The exe ution of the alling subprogram, i.e. the subprogram whi h ontains the all,
main program, in this ase, is suspended. The alling subprogram will be resumed
later. When resumed, the exe ution will ontinue from where it was suspended.
3. Preparations are made to start running a subprogram. The subprogram will exe ute
the ode given in the body of the fun tion. The subprogram must be given a separate
area of memory so that it an have its own variables. It is ustomary to refer to this
area as the a tivation frame of the fun tion all. Immediately, spa e is allo ated in
the a tivation frame for storing the variables orresponding to the parameters of the
fun tion.
Thus in our ase, an a tivation frame is reated orresponding to the all g d(a,b).
The g d fun tion has two parameters, L, S. So variables, L and S will be reated in
the a tivation frame.
4. The value of the rst argument is opied to the memory asso iated with the rst
parameter. The value of the se ond argument to the se ond parameter, and so on.
Thus, in our ase, 36 will be opied into the variable L, and 24 into the variable S in
the a tivation frame reated for the all g d(a,b). Figure 9.2(a) shows the state of
the memory at this time. We have referred to the memory area used by main program
as its a tivation frame. This is ustomary.
5. Now the body of the alled fun tion is exe uted. The body must refer to variables
or parameters stored only in the a tivation frame of the all. If spa e needs to be
1

reserved for variables et ., it is done only inside the a tivation frame of the all.
Thus in ase of our program, the ode may refer to the parameters L, S. The ode
annot refer to variables a,b, ,d be ause they are not in the a tivation frame of
g d(a,b). When the rst statement of the body is exe uted, it auses the reation of
the variable Remainder. The spa e for this is allo ated in the a tivation frame of the
all. Su h variables are said to be lo al to the all.
1 We will modify this a bit later.
Abhiram Ranade, 2013. Do not distribute 145
6. The body of the fun tion is exe uted until a return statement is en ountered. The
expression following return is alled the return-expression and its value is sent ba k
to the alling program. The value sent ba k is onsidered to be the value of the all in
the alling program.
In our ase the exe ution of the fun tion happens as follows. In the rst iteration of
the loop, L, S have values 36,24. At the end of this iteration, the values be ome 24,12.
The state of the memory at this point is shown in Figure 9.2(b). In the next iteration,
Remainder be omes 0, and so the break statement is exe uted. Thus the ontrol exits
from the loop, and return is rea hed. The return-expression is S whi h has value
12. This value is sent ba k to the alling program.
7. The a tivation frame reated for the all is not needed any longer, and is destroyed,
i.e. that area is marked available for general use.
8. The alling program resumes exe ution from where it had suspended. The returned
value is used as the value of the all itself.
In our ase the all was g d(a,b), and its value is required to be printed. Thus the
value returned, 12, will be printed. After this the next out statement will be exe uted
(in whi h we will en ounter the se ond all to g d). This will ause an a tivation frame
to be reated again et .
In this model of exe uting fun tion alls, only the values of the arguments are sent from the
alling program to the alled fun tion. For this reason, this model is often termed as all by
value. We will see another model later on.
It is worth onsidering what happens on the se ond all to g d, i.e. the all g d( ,d) in
the ode. The same set of a tions would repeat. A new a tivation frame would be reated
for this all, and very likely it would use the same memory as was used for the a tivation
frame of the previous all. The point to be noted is that ea h all requires some additional
memory, but only for the duration of the exe ution of the all.
9.1.2 Names of parameters and lo al variables
We have already said that when a fun tion all exe utes, it an only a ess the variables
(in luding the parameters) in its a tivation frame. In parti ular, the variables in the alling
program (in this ase main program) annot be a essed. So it is perfe tly ne if variables
in the alling program and the alled fun tion have the same name! Note further that when
the alling program is exe uting, the a tivation frame of the alled fun tion does not even
exist, so there is no question of any onfusion.

9.2 Nested fun tion alls: LCM


Suppose now that you wish to develop a program to ompute the least ommon multiple
(LCM) of two numbers. This is easily done using the following relationship between the
LCM, L, and the GCD, G of two numbers m; n:
mn
L=
G
Abhiram Ranade, 2013. Do not distribute 146
A tivation frame of main program A tivation frame of g d(a,b)
a : 36 L : 36
b : 24 S : 24
: 99
d : 47

(a) After opying arguments.


A tivation frame of main program A tivation frame of g d(a,b)
a : 36 L : 24
b : 24 S : 12
: 99 Remainder : 12
d : 47

(a) At the end of the rst iteration of the loop in g d.


Figure 9.2: Some snapshots from the exe ution of g d(a,b)
It would of ourse be ni e to write a fun tion for the LCM, so that we ould invoke it
whenever needed, rather than having to opy the ode. We ould use the above relationship,
but that would require us to ompute the GCD itself. Does it mean that we need to rewrite
the ode for omputing the GCD inside the fun tion to ompute LCM? Not at all. We an
simply all the g d fun tion, sin e we have already written it! So here is how we an de ne
a fun tion to ompute the LCM.
int l m(int m, int n){
return m*n/g d(m,n);
}
The exe ution of l m follows the same idea as in our dis ussion earlier for g d. Suppose l m
is alled in by a main program as follows.
main_program{
out << l m(36,24) << endl;
}
When we exe ute the main program, we will need to run a subprogram for l m, whi h
involves reating the a tivation frame for this all. As this subprogram exe utes, we will
en ounter the expression g d(m,n) with m,n taking the values 36,24. To pro ess this all,
we will need to start a subprogram for g d. So at this point, we will have 3 a tivation
frames in memory, one for main program, one for l m(36,24) and another for g d(36,24).
This is perfe tly ne! When the subprogram for g d(36,24) nishes, then the result, 12,
will be sent ba k to the subprogram for l m(36,24). The result 12, will be used as the
value of the all g d(m,n). Thus the expression m*n/g d(m,n) an now be evaluated to
be 36*24/12=72. This will in fa t be the value that the subprogram l m(36,24) returns
ba k to main program. At this point, the omputation of main program will resume with
the re eived value.
Abhiram Ranade, 2013. Do not distribute 147
9.3 The ontra t view of fun tion exe ution
While it is important to know how a fun tion all exe utes, while thinking about fun tions,
a di erent, metaphori al view is useful.
The idea is to think of a fun tion all as giving out a ontra t to get a job done. We think
of the main program as an agent doing its work as des ribed in its program. Suddenly, the
agent en ounters a statement su h as l m(36,24). Rather than doing the work required to
ompute l m(36,24) itself, the main program agent engages another agent. This agent is
the subprogram for the all l m(36,24). The main program agent sends the input data to
the subprogram agent, and waits for the result to be sent ba k. This is not unlike engaging a
tailor, giving the tailor the loth and measurements, and waiting for the tailor to send ba k
a shirt.
The similarity extends further. There is nothing to prevent the tailor from further on-
tra ting out the work to others. It so happens, that stit hing the ollar of a shirt is a
spe ialized job, whi h most tailors would in fa t ontra t out to ollar-spe ialists. Thus it is
possible that we may be waiting for the tailor to send us ba k the shirt, and the tailor might
be waiting for the ollar spe ialist to send ba k a ollar. Noti e that this is very similar to
main program waiting for l m(36,24) whi h in turn is waiting for g d(36,24).

9.3.1 Fun tion spe i ation


A key point to be noted from the tailor example above is that when we ask for a shirt to be
stit hed, we generally do not worry about what the tailor will do. The tailor may do all the
work, or sub ontra t it out further to one or more raftsmen { that is not our on ern. We
merely fo us on the promise that the tailor has made to us { that a shirt will be delivered
to us. We dont worry about how the tailor does it, but we merely hold the tailor to deliver
us a good shirt (and at the right time and pri e, as per what has been agreed). If we tried
to worry about what our tailor should be doing, and what our a ountant should be doing,
and what our do tor should be doing, and so on, we would probably go mad!
Likewise, when we all a fun tion in our program, we do not think of how exa tly it
will get exe uted. We merely ask: what exa tly is being promised in the exe ution of this
fun tion? The promise, is a tually both ways, like a ontra t and is ustomarily alled the
spe i ation of the fun tion. The spe i ation of g d ould be as follows:
A all g d(m,n) returns the greatest ommon divisor of m,n, where m,n must
be positive integers.
You will noti e that the spe i ation lays down the responsibilities of both the alling pro-
gram, and the alled program.
1. Responsibilities of the alling program: To supply only positive integers as arguments.
Noti e that C++ already prevents you from supplying fra tional values when you
de lare the type of L, S to be int. However, nothing prevents a alling program from
supplying negative values or 0. The spe i ation says that the programmer who wrote
the fun tion g d makes no guarantees if you supply 0 or negative values. The onditions
that the input values are required to satisfy are often alled the pre- onditions of the
Abhiram Ranade, 2013. Do not distribute 148
fun tion. In addition, the alling program might also have to deal with post- onditions,
as will be dis ussed in Se tion 9.4.
2. Responsibilities of the alled program: If the alling program full lls its responsibilities
(i.e. the arguments satisfy the pre onditions), and only if the alling program full lls
its responsibilities, is the alled program obliged to do whatever was promised. There
is no telling what will happen if the pre onditions are not satis ed. Thus in ase of
g d, if a negative value or zero is supplied: nonsense values may be returned, or the
program may never terminate, or terminate with an error.
It is extremely important to learly write down the spe i ation of a fun tion. You may
sometimes avoid doing so, thinking that the spe i ation is obvious. But it may not be so!
For example, a more general de nition of GCD might allow one of the numbers to be zero,
in whi h ase the other number is de ned to be the GCD. If this is the de nition a user
is familiar with, he/she might supply 0 as the value of the se ond parameter n. This will
ertainly ause the program to terminate be ause of a division by zero in the very rst step
of our ode. To prevent su h misunderstandings, it is best to write down the spe i ations
in full detail.
The natural pla e to write down the spe i ation is immediately before the fun tion
de nition. So your fun tion for g d should really look like the following.
int g d(int L, int S)
// Fun tion for omputing the greatest ommon divisor of integers L, S.
// PRE-CONDITION: L, S > 0
{
...
}
Please get into the habit of writing spe i ations for all the fun tions that you write. Note
that in the spe i ation it is important to not write how the fun tion does what it does, but
only what the fun tion does, and for what pre onditions.
A des ription of how the fun tion does what it does, often referred to as the des ription
of the implementation of the fun tion is also important. But this should be kept separate
from the spe i ation. The des ription of how an be in a separate do ument, or ould be
written as omments in the body of the ode of the fun tion. For example, the following
omment might be useful to explain how the g d fun tion works.
// Note the theorem: If n divides m, then GCD(m,n) = n.
// If n does not divide m, then GCD(m,n) = GCD(n, m mod n)
This omment ould be pla ed at the beginning of the loop.

9.4 Fun tions that do not return values


Every fun tion (or ommand) does not need to return a value. You have already seen su h
fun tions, e.g. forward, whi h auses the turtle to move forward, but itself does not stand
Abhiram Ranade, 2013. Do not distribute 149
for any value. The ommand forward is prede ned for you, but you an also de ne new
fun tions or ommands that do something and do but do not return a value.
For example, you might wish to build a fun tion whi h draws a polygon with a given
number of sides, and having a ertain given sidelength. Clearly, it must take two arguments,
an integer giving the number sides, and a double giving the side length. Suppose we name
it polygon. The fun tion does not return any value, so we are required to spe ify the return
type in the de nition to be void. Also, sin e nothing is being returned, we merely write
return with no value following it.
void polygon(int nsides, double sidelength)
// draws polygon with spe ified sides and spe ified sidelength.
// PRE-CONDITION: The pen must be down, and the turtle must be
// positioned at a vertex of the polygon, pointing in the lo kwise
// dire tion along an edge.
// POST-CONDITION: At the end the turtle is in the same position and
// orientation as at the start. The pen is down.
{
for(int i=0; i<nsides; i++){
forward(sidelength);
right(360.0/nsides);
}
return;
}
Note the pre ondition: it states where the polygon is drawn in omparison to where the
turtle is pointing. Similarly, we should mention where the turtle is at the end, this will be
needed in order to know how to draw subsequently. A ondition su h as this one, whi h will
be true after the exe ution of the fun tion, is said to be a post- ondition of the fun tion. A
post- ondition is also a part of the spe i ation.

9.5 A text drawing program


We would like to develop a program using whi h it is possible to write on the s reen using
our turtle. For example, we might want to write \IIT MUMBAI". How should we organize
su h a program?
A natural (but not ne essarily the best, see the exer ises) way of organizing this program
is to have a separate fun tion for writing ea h letter. For example, we will have a fun tion
drawI for drawing the letter 'I'. Suppose we de ide that we will write in a simple manner, so
that the letter 'I' is just a line, without the serifs (horizontal lines at the top and bottom),
i.e. as .
I

What is the spe i ation of drawI? Clearly it must draw the line as needed. But where
should the line get drawn? This must be mentioned in the spe i ations. It is tempting to
say that the line will get drawn at the urrent position of the turtle, in the dire tion the
turtle is pointing. Is this really what we want? Keep in mind that you dont just want to draw
one letter, but a sequen e of letters. So it is important to bring the turtle to a onvenient
position for drawing subsequent letters. And what is that onvenient position?
Abhiram Ranade, 2013. Do not distribute 150
Suppose we think of ea h letter as being ontained inside a re tangle. It is ustomary to
all this re tangle the bounding-box of the letter. Then we will make it a onvention that the
turtle must be brought to the bottom left orner of the bounding box, and point towards
the dire tion in whi h the writing is to be done. Where would we like the turtle to be at the
end of writing one hara ter so that the next hara ter an be written easily? Clearly, the
most onvenient nal position is pointing away from the right bottom orner, pointing in
the dire tion of writing. We must also learly state in the pre ondition whether we expe t
the pen to be up or down. Also whether the inter- hara ter spa e is a part of the bounding
box or not. If the spa e is a part of the bounding box, a natural question arises: is it on
both sides of the hara ter or only on one side (whi h?)? We should not only answer these
questions, but must also in lude the answers in the spe i ation.
Based on the above onsiderations, drawI ould be de ned as follows.
void drawI(double ht, double sp){
/*Draws the letter I of height ht, leaving sp/2 units of spa e on both
sides. Bounding box in ludes spa e.
PRECONDITION: The turtle must be at the left bottom of the bounding-box
in whi h the hara ter is to be drawn, fa ing in the dire tion of
writing. Pen must be up.
POSTCONDITION: The turtle is at the bottom right orner of the
bounding-box, fa ing the writing dire tion, with pen up. */

forward(sp/2);
penDown();
left(90);
forward(ht);
penUp();
left(180);
forward(ht);
left(90);
forward(sp/2);
return;
}
Fun tions for other letters are left as exer ise for you. So assume that you have written
them. Then to write our message, our main program ould be as follows.
main_program{
int ht=100, sp=10;
turtleSim();
left(90); // turtle is pointing East at the beginning.
drawI(ht,sp);
drawI(ht,sp);
drawT(ht,sp);
forward(sp);
drawM(ht,sp);
Abhiram Ranade, 2013. Do not distribute 151
drawU(ht,sp);
drawM(ht,sp);
drawB(ht,sp);
drawA(ht,sp);
drawI(ht,sp);
loseTurtleSim();
}

A remark is in order. You will see that there are lo al variables named ht and sp in the main
program, as well as the fun tions have parameters alled ht and sp. This is a eptable. When
the fun tion is being exe uted, the exe ution refers only to its a tivation frame, and hen e
the variables in the main program are not visible. When the main program is exe uting, the
a tivation frame of the fun tions is not even present, so there is no onfusion possible.

9.6 Some diÆ ulties


There are a few seemingly simple things we annot do using our urrent notion of a fun tion.
For example, we might want to write a fun tion whi h takes as arguments the Cartesian
oordinates of a point and returns the Polar oordinates. This is not immediately possible
be ause a fun tion an only return one value, not two. Another example is: suppose we want
to write a fun tion alled swap whi h ex hanges the values of two integer variables. Suppose
we de ne something like the following.
void swap(int a, int b){ // will it work?
int temp;
temp = a;
a = b;
b = temp;
}
If we all this by writing swap(p,q) from the main program, we will see it does not hange
the values of p,q in the main program. The reason for this is that when swap exe utes,
it does ex hange the values a,b, but a,b are in the a tivation frame of swap, and their
ex hange does not have any e e t on the values of p,q whi h are in the a tivation frame of
the main program.
As a third example, onsider the mark averaging program from Chapter 7. An important
step in this program is to read the marks from the keyboard and he k if the marks equal
200. If the marks equal 200, then the loop needs to terminate. Here is an attra tive way to
write the program.
int main(){
double nextmark, sum=0;
int ount=0;

while(read_marks_into(nextmark)){ // will this work?


sum = sum + nextmark;
Abhiram Ranade, 2013. Do not distribute 152
ount = ount + 1;
}

out << ``The average is: `` << sum/ ount << endl;
}

Our hope is that we an write a fun tion read marks into that will behave in the following
manner. It will read the next mark into the variable given as the argument, and also return
a true or false depending upon whether the reading was su essful, i.e. true if the value read
was not 200, and false if it was. But what we have learned so far does not allow us to write
this fun tion: The value of the argument nextmark will be opied to the parameter of the
fun tion, but will not be opied ba k.
It turns out that all the 3 problems listed above have a ni e solution in C++. This
solution is based on another way of passing arguments to fun tion, alled all by referen e.
We will see this next.
Following that we will see how the problem is solved in the C language. As you might
know, C++ is onsidered to be an enhan ed version of C. There are a number of reasons for
dis ussing the C solution. First of all, it is good to know the C solution be ause C is still in
use, substantially. Also, you may see our so alled C solution in C++ programs written by
someone, be ause essentially all C programs are also C++ programs. Se ond, the C solution
uses the notion of pointers, whi h are needed in C++ also. Finally, the C solution is in fa t
a less magi al version of the all by referen e solution of C++. So in ase you are, the C
solution might help you understand \what goes on behind the s enes" in all by referen e.

9.7 Call by referen e


The idea of all by referen e is simple: when you make a hange to a fun tion parameter
during exe ution, you want the hange to be re e ted in the orresponding argument? Just
say so and it is done! The way to \say so" is to de lare the parameter whose value you
want to be re e ted as a referen e parameter, by adding an & in front of the name of the
parameter. So here is how we might write the fun tion to onvert from Cartesian to Polar.
void Cartesian_To_Polar(double x, double y, double &r, double &theta){
r = sqrt(x*x + y*y);
theta = atan2(y,x);
}
In this fun tion, r and theta have been de lared to be referen e parameters. No storage
is allo ated for a referen e parameter in the a tivation frame of the fun tion, nor is the
value of the orresponding argument opied. Instead, during the exe ution of the fun tion, a
referen e parameter dire tly refers to the orresponding argument. Hen e whatever hanges
the fun tion seems to make to a referen e parameter are really made to the orresponding
argument dire tly.
This an be alled in the normal way, possibly as follows.
int main(){
Abhiram Ranade, 2013. Do not distribute 153
double x1=1.0, y1=1.0, r1, theta1;
Cartesian_To_Polar(x1,y1,r1,theta1);
out << r1 << ' ' << theta1 << endl;
}
Here is how the all CartesianToPolar(x1,y1,r1,theta1) exe utes. The values of x1,y1
are opied to the orresponding parameters x,y. However, as mentioned, the values of r1,
theta1 are not opied. Instead, all referen es to r, theta in the fun tion are deemed to
be referen es to the variables r1,theta1 instead! Thus, as CartesianToPolar exe utes, the
assignments in the statements r=... and theta=... get made to r1 and theta1
p dire tly.
So indeed, when the fun tion returns, the variable r1 would ontain p1 + 1 = 2  1:4142,
and theta1 would ontain tan 1 = =4  0:785, and these would be printed out.
1

The fun tion to swap variable values an also be written in a similar manner.
void swap2(int &a, int &b){
int temp;
temp = a;
a = b;
b = temp;
}
This an be alled as follows.
int main{
int x=5, y=6;
swap2(x,y);
out << x << " " << y << endl;
}
Both the arguments of swap2 are referen es, and so nothing is opied into the a tivation
area of swap2. The parameters a,b refer dire tly to x,y, i.e. e e tively we exe ute
temp = x;
x = y;
b = temp;
This will learly ex hange the values of x,y, so at the end \6 5" will be printed.
Our last example is the read marks into fun tion dis ussed in Se tion 9.6.
bool read_marks_into(int &var){
in >> var;
return var != 200;
}
This de nition will work as desired with the main program given in Se tion 9.6. When the
fun tion exe utes, the rst line will read a value into var. But var is a referen e for the
orresponding parameter nextmark, and hen e the value will in fa t be read into nextmark.
The expression var != 200 is true if var is not 200, and false if it is 200. So the while
loop in the main program will indeed terminate as soon as 200 is read. Continuing the
dis ussion at the end of Se tion 7.2, we note that perhaps this is the ni est way of writing
the mark averaging program: we do not dupli ate any ode, and yet the loop termination is
by he king a ondition at the top, rather than using a break statement in the body.
Abhiram Ranade, 2013. Do not distribute 154
9.7.1 Remarks
Call by referen e is very onvenient. However two points should be noted.
The manner by whi h we spe ify arguments of a fun tion in a all is the same, no matter
whether we use all by value or by referen e for a parameter. This makes it hard to read
and understand ode. When we see a fun tion all, we need to either nd the fun tion
de nition or de laration (Se tion 11.2.1) to know whi h of the arguments, if any, orrespond
to referen e parameters, and hen e might hange when the fun tion returns. The C language
solution whi h uses pointers, dis ussed next, does not have this drawba k. On the other had
it has other drawba ks, as you will see.
If a ertain parameter in a fun tion is a referen e parameter, then the orresponding
argument must be a variable. For example, we annot write swap2(1,z). This would make
a,b refer to 1,z respe tively and then statements in the fun tion su h as a = b; would have
to mean something like 1 = z;, whi h is meaningless. So supplying anything other than a
variable is an error if the orresponding parameter is a referen e parameter. However, also
see the dis ussion about onst referen e parameters in Se tion 15.2.1.
9.7.2 Referen e variables
In the dis ussion above we noted that a referen e parameter should be thought of as just a
name, what it is a name of is xed only when we make the all. In a similar manner, we an
have referen e variables also.
int x = 10;
int &r = x;
out << r << endl;
r = 20;
out << x << endl;
The rst statement de nes the variable x and assigns it the value 10. The se ond statement
de lares a referen e r, hen e the & before the name. In the de laration itself we are obliged
to say what the name r is refers to. This is spe i ed after =. Thus the se ond statement
de lares the integer referen e r whi h is a referen e to x, or just another name for the variable
x. In the third statement, we print r, sin e this is a name for the variable x, the value of
that, 10, gets printed. In the fourth statement, we assign 20 to r, but sin e r is just a name
for x, it really hanges the value of x. Finally, this hanged value, 20, gets printed in the last
statement.
The utility of referen e variables will be ome lear later, in Se tion 25.3.3.

9.8 Pointers
We rst dis uss pointers in general, and then say how they are helpful in solving the problems
of Se tion 9.6.
We know from Se tion 2.5.1 that memory is organized as a sequen e of bytes, and the
ith byte is supposed to have address i, or be at address i. When memory is allo ated to a
variable, it gets a set of onse utive bytes. The address of the rst byte given to the variable
is also onsidered to be the address of the variable.
Abhiram Ranade, 2013. Do not distribute 155
9.8.1 \Address of" operator &
C++ provides the unary operator & (read it as \address of") whi h an be used to nd
the address of a variable. It is alled unary be ause it is to be applied only to a single
expression, as you will see. Yes, this is the same hara ter that we used to mark a parameter
as a referen e parameter, and there is also a binary operator & (Se tion E). But you will be
able to tell all these apart based on the ontext. Here is a possible use of the unary &.
int p;
out << &p; // In this operator & is applied to p.
This will print out the address of p. Note that the onvention in C++ is to print out
addresses in hexade imal, so you will see something that begins witn 0x, whi h indi ates
that following it is an hexade imal number. Note that in hexade imal ea h digit takes value
between 0 and 15. Thus some way is needed to denote values 10, 11, 12, 13, 14, 15, and for
these the letters a,b, ,d,e,f respe tively are used.
9.8.2 Pointer variables
We an store addresses into variables if we wish. But for this we need to de ne variables of
an appropriate type. For example, we may write:
int p=15;
int *r; // not ``int multiplied by r''! See below.
r = &p;
out << &p << " " << r << endl;
The rst statement de lares a variable p as usual, of type int. The next statement should
be read as (int*) r;, i.e. int* is the type and r is the name of the de lared variable. The
type int* is used for variables whi h are expe ted to ontain addresses of int variables.
This is what the third statement does, it stores the address of the int type variable p into
r. If you exe ute this ode, you will see that the last statement will indeed print identi al
hexade imal numbers.
Figure 9.3 s hemati ally shows a snapshot of memory showing the e e t of storing the
address of p into r. In this we have assumed that p is allo ated bytes 104 through 107, and
r is allo ated bytes 108 through 111. The address of p, 104, appears in bytes 108 through
111, as a result of the exe ution of r = &p;.
Likewise we may write:
double q;
double* s = &q;
Here we have de lared and initialized s in the same statement. Note that double* and int*
are di erent types, and you may not write s = &p; or r = &q;.
Variables r,s are said to be pointers to p,q. In general, variables of type T* where T
is a type are said to be pointer variables.
Finally, even though we use integers to number memory lo ations, it is never ne essary
in C++ programs to expli itly store a spe i onstant, say 104, into a pointer variable. If
Abhiram Ranade, 2013. Do not distribute 156
Address Content Remarks
104
105 15 Allo ated to p
106
107
108
109 104 Allo ated to r
110
111
Figure 9.3: Pi ture after exe uting r = &p;

you somehow ome to know that 104 is the address of a ertain variable v, and so you want
104 stored in some pointer variable w, then you an do so by writing w = &v;, without using
the number 104 itself. In fa t, it is a ompiler error in C++ to write something su h as
w=104, where w is a pointer, e.g. of type int*. Be ause you dont need to write this, if you
a tually do, it is more likely to be a typing mistake. So the ompiler ags it as an error.
Finally it should be noted that C++ de larations are a bit onfusing. The following
int* p, q; // both pointers?

de lares p to be a pointer to int, while q is simply an int. Even if you put no spa e between
int and * in the above statement, the * somehow \asso iates" with p than with int.

9.8.3 Dereferen ing operator *


If we know the address of a variable, we an get ba k that variable by using the dereferen ing
operator, *. Very simply put, the unary * an be onsidered to be the inverse of &. The
hara ter * also denotes the multipli ation operator, and is also used in de laration of pointer
variables, but it will be lear from the ontext whi h operator is meant.
Formally, suppose xyz is of type T* and has value v. Then we onsider the memory at
address v to be the starting address of a variable of type T, and *xyz denotes this variable.
The unary * is to be read as \ ontent of", e.g. an expression su h as *xyz above is to be
read as \ ontent of xyz".
For an example, onsider the de nitions of p,r as given above. Then to nd what *r
means, we note that r is of type int* and has value &p. Thus *r denotes a variable of type
int stored at address &p. But p is exa tly su h a variable. Hen e *r denotes the variable p
itself. Thus, if *r were to appear on the left hand side of an assignment statement, we would
really be storing a value into p. If *r appeared on the right hand side of an assignment, or
in an expression, we would be using the value of p in pla e of the expression *r. Thus we
may write (after the ode int p=15; int *r; r = & p;):
*r = 22;
int m;
m = *r;
Abhiram Ranade, 2013. Do not distribute 157
In the rst statement, we would store 22 into p. In the third statement, we would store the
value of p, 22 in this ase, into m.
9.8.4 Use in fun tions
We rst note that fun tions an take data of any type as arguments, in luding types su h
as int* or double*. Thus we an write a fun tion to ompute the polar oordinates given
Cartesian as follows.
void CartesianToPolar(double x, double y, double* pr, double* ptheta){
*pr = sqrt(x*x + y*y);
*ptheta = atan2(y,x);
}
This ould be alled as follows.
int main{
double r,theta;
CartesianToPolar(1.0, 1.0, &r, &theta);
out << r << `` `` << theta << endl;
}

Let us rst make sure that the types of the arguments in the all and the parameters in
the fun tion de nition mat h. The rst and se ond parameters, x, y are required to be a
double, and indeed the rst and se ond arguments are both 1.0, of type double. The third
parameter pr is of type double*. The third argument is the expression &r, whi h means the
address of r. Sin e r is of type double, the type of &r is indeed double*, and hen e the
type of the third argument and the third parameter mat h. Similarly the type of the fourth
argument &theta is also seen to mat h the type double* of the fourth parameter. So learly
our program should ompile without errors.
Let us see how this will exe ute. When the fun tion CartesianToPolar is alled, none
of the parameters are referen e parameters, and so all arguments have to be opied rst. So
1.0 is opied to the parameter x in the a tivation frame of CartesianToPolar. The se ond
argument 1.0 is opied to y. The third argument &r is opied to pr, and nally the fourth
argument &theta is opied to ptheta.
Then the body of the fun tion is exe uted.
p The rst statement is *pr = sqrt(x*x +
y*y);. The right hand side evaluates to 2, be ause x and y are both 1. This value is to
be pla ed in the variable denoted by the left hand side. Now *pr is interpreted exa tly as
des ribed in Se tion 9.8.3. Given that pr is of type double*, the expression *pr denotes
that double variable whose address appears in pr. But we pla ed the address of r of the
main program in pr. Hen e *pr denotes the variable r of the main program. Hen e the
statement
p *pr=sqrt(x*x + y*y), even if it appears in the ode of CartesianToPolar will
store 2 into the variable r of main.
Next let us onsider the statement *ptheta = atan2(y,x);. Sin e y,x are both 1, the
ar tangent will be found to be =4  0:785. Reasoning as before, the expression *ptheta
will denote the variable theta of the main program. Thus 0.785 will be stored in theta of
Abhiram Ranade, 2013. Do not distribute 158
p
main. After this the all will terminate. When the exe ution of main resumes, 2 and 0.785
would get printed by the last statement in main.
We next onsider the swap fun tion. It should be lear to you now what we should
do: instead of using the variables as arguments, we should use their addresses. Here is the
fun tion.
void swap(int* pa, int* pb){
int temp;
temp = *pa;
*pa = *pb;
*pb = temp;
}
It may be alled by a main program as follows.
int main{
int x=5, y=6;
swap(&x,&y);
out << x << `` ``<< y << endl;
}
The arguments to the all are &x, &y, having type int*, be ause x,y are of type int. Thus
they mat h the types of the parameters of the fun tion. Thus our program will be ompiled
orre tly.
So let us onsider the exe ution. The address of x will be opied into pa, and the address
of y into pb. Thus we may note that *pa in swap will really refer to the variable x of the main
program, and *pb in swap will refer to the variable y of the main program. The statement
temp = *pa; will ause the value of x to be opied to temp. In the next statement, the value
of y is opied to x. The last statement auses the value in temp, i.e. the value in x at the
beginning to be opied to y (whi h is what *pb denotes). The fun tion all ompletes. The
main program then resumes and will print the ex hanged values, 6 and 5.
The hanges required to the main program for mark averaging and the fun tion read marks into
are left as exer ises.
9.8.5 Referen e vs. Pointers
You have seen that there are two ways of writing the fun tions Cartesian To Polar, swap
and read marks into. Whi h one is better?
Clearly, the fun tions are easier to write with all by referen e. So that is learly to be
re ommended in C++ programs. 2

You are probably wondering: when a fun tion exe utes, and some parameter is a referen e parameter,
2
how does the omputer know what variable the parameter refers to? A simple answer is: at the time of
the all, C++ automati ally sends the address of the variables referred to by the referen e parameters to
the fun tion a tivation frame. Also, during the fun tion exe ution, C++ itself dereferen es the address of
the referen e variables, and gets to the variables as needed. So in other words, the operations of sending
addresses and dereferen ing them that had to be manually written out in C are performed \behind the
s enes" by C++.
Abhiram Ranade, 2013. Do not distribute 159
9.9 Returning referen es and pointers
It is possible to return referen es and pointers from fun tions. But this has to be done
with are. We will explain the idea, but for interesting use of it you will have to wait till
Se tion 16.4, Se tion 19.3.3 or Se tion 19.3.4.
First of all, in order to return a referen e to a type T the return type of the fun tion must
be given as T&, as you might expe t. Here is an example.
int &f(int &x, int &y){
if(x > y) return x;
else return y;
}
main_program{
int p=5, q=4;
f(p,q) = 2; // fun tion all appears on the left!
out << p <<' '<< q << endl;
out << f(p,q) << endl;
}
This main program ontains a fun tion all on the left hand side of an expression! Normally,
a fun tion returns a value, and there is no notion of assigning one value to another value!
However, we an ertainly assign a value to a referen e, and hen e a fun tion that returns a
referen e an indeed be on the left hand side of an assignment statement. Thus the statement
will exe ute by evaluating the value of the right hand side, whi h will then be pla ed in the
variable that the left hand side refers to.
So onsider the exe ution of f(p,q)=2; in the above ode. Noting that p,q are being
passed by referen e, the referen es x,y will refer respe tively to the variables p,q of the main
program. Thus the expression x>y is identi al to p>q, where p,q are variables in the main
program. Thus x>y will evaluate to true. Thus the statement return x; will be exe uted.
Be ause the fun tion has return type referen e to int (int), the value of x (whi h is the
value of the variable it refers to) is not returned, but the referen e itself is returned. Sin e x
is a referen e to p, the all returns a referen e to p. But then the main program statement
f(p,q) = 2; is equivalent to p = 2;. Hen e the statement will ause p to be ome 2. Thus
the print statement will print \2 4".
Note that a all to a fun tion that returns a referen e does not have to be on the left hand
side of the assignment. Indeed, in the last line, we print f(p,q). When this all exe utes,
x,y refer to p,q as you might expe t. The omparison x>y is now false, be ause p now has
value 2. Thus y is returned by referen e, i.e. a referen e to q is returned. Thus the last
statement, out << f(p,q) << endl; is equivalent to the statement out << q << endl;,
and hen e the value 4 will get printed.
It should be noted that returning a referen e an be dangerous.
double &h(){
double x = 5;
return x;
}
int main(){
Abhiram Ranade, 2013. Do not distribute 160
h() = 7;
}
The fun tion all h() will return a referen e to the lo al variable x of the fun tion. Un-
fortunately, after the fun tion returns, the lo al variable will no longer exist! Thus in the
main program it will be in orre t to either modify h() or get its value. Note that most
C++ ompilers will not give any errors for the ode above. However, this ode is de nitely
in orre t.
Similar ideas apply to returning pointers. The analogue of the rst example above is as
follows.
int *f(int *x, int *y){
if(*x > *y) return x;
else return y;
}
int main(){
int p=5, q=4;
*f(&p,&q) = 2;
out << p <<' '<< q << endl;
out << *f(&p,&q) << endl;
}
In this, the all f(&p,&q) returns the address of a variable, so it an be dereferen ed and
then we an either modify the variable or get its value. Thus the rst print statement will
print \2 4" and the se ond will print 4 as before.
Analogously it is in orre t to return the address of a variable that will be deallo ated by
the time the address an be used.
double *h(){
double x = 5;
return &x;
}
int main(){
*h() = 7;
}
The fun tion all h() returns the address of the variable x lo al to the fun tion all. The
variable is destroyed when the fun tion all returns. Hen e it is in orre t to use h() in any
way in main.

9.10 Default values of parameters


It is possible to assign default values to parameters of a fun tion. If a parti ular parameter
has a default value, then the orresponding argument may be omitted while alling it. The
default value is spe i ed by writing it as an assignment to the parameter in the parameter
list of the fun tion de nition. Here is a polygon fun tion in whi h both parameters have
default values.
Abhiram Ranade, 2013. Do not distribute 161
void polygon(int nsides=4, double sidelength=100)
{
for(int i=0; i<nsides; i++){
forward(sidelength);
right(360.0/nsides);
}
return;
}

Given this de nition, we are allowed to all the fun tion either by omitting the last argument,
in whi h ase the sidelength parameter will have value 100, or by omitting both parameters,
in whi h ase the nsides parameter will have value 4 and sidelength will have value 100. In
other words, we an make a all polygon(5) whi h will ause a pentagon to be drawn with
side length 100. We an also make a all polygon() for whi h a square of sidelength 100 will
be drawn. We are free to supply both arguments as before, so we may all polygon(8,120)
whi h will ause an o tagon of sidelength 120 to be drawn.
In general, we an assign default values to any suÆx of the parameter list, i.e. if we wish
to assign a default to the ith parameter, then a default must also be assigned to the i + 1th,
i + 2th and so on.
Further, while alling we must supply values for all the parameters whi h do not have
a default value, and to a pre x of the parameters whi h do have default values. In other
words, if the rst k parameters of a fun tion do not have default values and the rest do, then
any all must supply values for the rst j parameters, where j  k.

9.11 Fun tion overloading


C++ allows you to de ne multiple fun tions with the same name, provided the fun tions
have di erent parameter type lists. This omes in handy when you wish to have similar
fun tionality for data of multiple types. For example, you might want a fun tion whi h
al ulates the g d of not just 2 numbers, but several, say 3 as well as 4. Here is how you
ould de ne fun tions for doing both, in addition to the g d fun tion we de ned earlier.
int g d(int p, int q, int r){
return g d(g d(p,q),r);
}

int g d(int p, int q, int r, int s){


return g d(g d(p,q),g d(r,s));
}
The above fun tions in fa t assume that the previous g d fun tion exists. Here is another
use. You migth want to have an absolute value fun tions for double data as well as int.
C++ allows you to give the name Abs to both fun tions.
int Abs(int x){
if (x>0) return x;
Abhiram Ranade, 2013. Do not distribute 162
else return -x;
}

double Abs(double x){


if (x>0) return x;
else return -x;
}
While it is onvenient to have the same name in both ases, you may wonder how does the
ompiler know whi h fun tion is to be used for your all. The answer is simple: if your all
is abs(y) where y is int then the rst fun tion is used, if the type is double then the se ond
fun tion is used. Likewise, the right g d fun tion will be pi ked depending upon how many
arguments you supplied.

9.12 Fun tion templates


You might look at the two abs fun tions we de ned in the pre eding se tion and wonder:
sure the fun tions work on di erent types, but the bodies are really identi al, ould we not
just give the body on e and then have the ompiler make opies for the di erent types? It
turns out that this an also be done using the notion of fun tion templates as follows.
A fun tion template does not de ne a single fun tion, but it de nes a template, or a
s heme, for de ning fun tions. The template has a ertain number of variables: if you x
the values of the variables, then you will get a fun tion! Here is an example.
template<typename T>
T Abs(T x){
if (x>0) return x;
else return -x;
}
The name T is the template variable. You an put in whatever value you want, and it will
de ne a fun tion. In fa t C++ will put in the value as needed! So if you have the following
main program
int main(){
int x=3;
float y=-4.6;

out << Abs(x) << endl;


out << Abs(y) << endl;
}
Then C++ will reate two Abs fun tions for you. On seeing the rst out statement, C++
will realize that it an reate an Abs fun tion taking a single int argument by setting T to
int. Likewise T will be set to float and another fun tion will be generated for use in the
last statement.
A more interesting example is given in the exer ises.
Abhiram Ranade, 2013. Do not distribute 163
Exer ises
1. Write a fun tion that prints the GCD of two numbers.
2. Modify the fun tion polygon so that it returns the perimeter of the polygon drawn (in
addition to drawing the polygon).
3. Write a fun tion to nd the ube root of a number using Newton's method. A ept
the number of iterations as an argument.
4. Write a fun tion to determine if a number is prime. It should return true or false,
i.e. be of type bool.
5. Write the fun tion read marks into and the main program for mark averaging using
pointers.
6. A key rule in assignment statements is that the type of the value being assigned must
mat h the type of the variable to whi h the assignment is made. Consider the following
ode:
int *x,*y, z=3, b[3℄;

x = &b;
y = &x;
z = y;
y = *x;
y = *b;

Ea h of the assignments is in orre t. Can you guess why? If not, write the ode in a
program, ompile it, and the ompiler will tell you!
7. Write a fun tion to nd roots of a fun tion f using Newton's method. It should take
as arguments pointers to f and also to the derivative of f.
p
8. The k-norm of a ve tor (x; y; z) is de ned as k xk + yk + zk . Note that the 2-norm is
in fa t the Eu lidean length. Indeed, the most ommonly used norm happens to be
the 2 norm. Write a fun tion to al ulate the norm su h that it an take k as well
as the ve tor omponents as arguments. You should also allow the all to omit k, in
whi h ase the 2 norm should be returned.
Chapter 10

Re ursive Fun tions

We are now in a position to dis uss what is perhaps the most powerful, most versatile problem
solving te hnique ever: re ursion. What we are going to present will not really ontain any
new C++ statements. Rather, what you have learned so far will be used, possibly in a
manner whi h might surprise you, to solve some diÆ ult omputational problems in a very
su in t manner.
A fundamental idea in designing algorithms is problem redu tion. The notion is very
ommon in Mathemati s, where we might say \Using the substitution y = x + x the 2

quarti (fourth degree) equation (x + x + 5)(x + x + 9) + 7 = 0 redu es to the quadrati


2 2

(y + 5)(y + 9) + 7 = 0.". Of ourse, redu ing one problem into another is useful only if the
new problem is in some sense easier than the original. This is true in our example: quadrati
equations are easier to solve than quarti . The strategy of redu ing a problem to another is
easily expressed in programs: the fun tion we write for solving the rst problem will all the
fun tion for solving the se ond problem. We saw examples of this in the previous hapter.
An interesting ase of problem redu tion is when the new problem is of the same type
as the original problem. In this ase the redu tion is said to be re ursive. This idea might
perhaps appear to be strange, but it is in fa t very ommon. Consider the following rules
for di erentiation: d d d
dx
(u + v) = u + v
dx dx
d d d
dx
(uv ) = v u + u v
dx dx
The rst rule, for example, states that the problem of di erentiating the sum u + v is the
same as that of rst di erentiating u and v separately, and taking their sum. You have
probably used these rules without realizing that they are re ursive. There are two reasons
why these rules work:
1. The redu ed problems are a tually simpler in some pre ise sense. In our example,
the problem of di erentiating u or of di erentiating v are indeed simpler than the
problem of di erentiating u + v, be ause u and v are both smaller expressions than
u + v . Noti e that when we redu e one problem to a problem of another type (non-
re ursive redu tion), the new problem is required to be of a simpler type. For re ursive
redu tion, it is enough if the new problem is of a smaller size.

164
Abhiram Ranade, 2013. Do not distribute 165
2. Eventually we must have a way to solve some problems dire tly { we annot just keep
redu ing problems inde nitely. The problems whi h we expe t to solve dire tly are
alled the base ases. Considering di erentiation again, suppose we wish to ompute:
d
dx
(x sin x + x)
Then using the rst rule we would ask to ompute
d d
x sin x + x
dx dx
Now, the omputation of dxd x is not done by further redu tion, i.e. this is a base ase
for the pro edure. So in this ase we dire tly write that dxd x = 1. To ompute dxd x sin x
wed ould use the produ t rule given above, and we would need to know the base ase
dx
sin x = os x.
Even on a omputer, re ursion turns out to be extremely useful. In this hapter we will see
several examples of the idea.

10.1 Eu lid's algorithm for GCD


Eu lid's algorithm for GCD is naturally expressed re ursively, as it turns out. Here is Eu lid's
theorem, restated for onvenien e.
Theorem 2 (Eu lid) Let m; n be positive integers. If m%n = 0 then GCD(m; n) = n. If
m%n 6= 0 then GCD(m; n) = GCD(n; m%n).
The theorem essentially says that either the GCD of m; n is n, or it is the GCD of
n; m%n. But this is exa tly like saying that the derivative of an expression an be written
down dire tly or it is the derivative of some simpler expression. Following the analogy, it
would seem tempting, to all g d from inside of itself.
int g d(int m, int n)
// finds GCD(m,n) for positive integers m,n
{
if(m % n == 0) return n;
else return g d(n,m % n);
}
And the most interesting thing is that it works! In the last hapter we sket hed out the
me hanism used to exe ute fun tions, and it turns out that the same me hanism will orre tly
ompute the GCD using the above ode. We will see an example and a general proof shortly.
The fun tion g d as de ned above alls itself. Su h fun tions are said to be re ursive.
Abhiram Ranade, 2013. Do not distribute 166
Fun tion all main g d(36,24) g d(24,12)
A tivation Frame m : 36 m : 24
ontents n : 24 n : 12
State of all Suspended Suspended Exe uting
Code with  out << if(m % n == 0)  if(m % n == 0)
showing next  g d(36,24) return n; return n;
statement to << endl; else return else return
be exe uted  g d(n, m % n); g d(n, m % n);

Figure 10.1: A snapshot of the exe ution of re ursive g d


10.1.1 Exe ution of re ursive g d
Suppose for the moment that our main program in addition the g d de nition above is:
int main(){ out << g d(36,24) << endl;}
Suppose the main program begins exe ution. Immediately it omes upon the all g d(36,24).
As we know, this auses an a tivation re ord to be onstru ted for the all, and in this a ti-
vation re ord the parameters m,n are assigned the value 36,24 respe tively.
Now the exe ution begins in the new a tivation re ord. The rst he k, m % n == 0
fails, be ause 36 % 24 is 12 and not 0. Thus we exe ute the else part. But this ontains
the all g d(n, m % n), i.e. g d(24,12). Our fun tion all exe ution me hanism must be
used again. Thus another a tivation re ord is reated, this time for g d(24,12), and m,n in
this re ord are set to 24,12 respe tively. Also, the exe ution of the urrent all, g d(36,24),
suspends. Figure 10.1 shows the state of the world at this time in the exe ution.
The exe ution begins in the new a tivation re ord. We exe ute the rst statement whi h
requires us to he k if m % n == 0, i.e. 24 % 12 == 0. This is indeed true. So we exe ute
the statement return n. This auses 12 to be returned. Where does this value go? It goes
ba k to the pla e from where the urrent re ursive all was made. Sin e the urrent all
was made while pro essing the se ond a tivation re ord, the value 12 is returned there. The
se ond a tivation then ontinues its exe ution. However, there isnt mu h more left to in this
a tivation. This ode was to return the value of g d(24,12) { now that this value is known,
12, it is returned ba k. So the value 12 is returned also from the se ond a tivation. This
goes ba k to the rst a tivation. The rst a tivation resumes from where it was suspended.
As per its ode, it prints out the re eived value, 12, and then main terminates.
So as you an see, the orre t value was omputed and printed.
The number of times a fun tion is alled is alled the depth of the re ursion. In the
present example, the depth is 2. For the example onsidered in Se tion 7.7, GCD(3977; 943)
you an he k that the depth will be 5, equalling the number of iterations required by the
program in Se tion 7.7. Please work this out by hand. You will also observe that the values
assigned to m,n in su essive a tivation re ords in the re ursive program are in fa t the same
values that m,n re eive in su essive iterations of the non-re ursive program in Se tion 7.7.
Abhiram Ranade, 2013. Do not distribute 167
10.1.2 Interpretation of re ursive programs
In some ways there is nothing more to be said about re ursive programs { the last se tion
said it all. We mentioned in the previous hapter that a fun tion all should be thought
of as ontra ting an agent to do the work you want, while you wait (are suspended). If
the work taken up by the agent is too ompli ated, then it is possible that the agent might
further sub- ontra t it out to another (sub-)agent. When this happens, you are waiting for
the agent to nish, the agent is herself waiting for the sub-agent to nish, and possibly the
hain might be very long. But so what?
Of ourse, the natural intuition is that you ontra t out work that you annot do yourself.
So it makes sense for the fun tion l m to ontra t out the work of g d as was done in the
last hapter. But whoever heard of ontra ting out work that you yourself an do? That is
in fa t what seems to be happening: the re ursive fun tion g d learly should know how to
ompute the GCD, and yet it seems to be sub ontra ting out work!
Suppose you have the task of building a Russian doll, whi h is a hildren's toy whi h
looks like a doll, but you an open up the doll to see that there is a doll inside, whi h ontains
another doll and so on till some fairly small doll is rea hed, whi h annot be further opened
up. Suppose further that we de ne a k level doll to be a doll whi h ontains k 1 dolls inside.
So let us say that your task is of building a k level doll. How would you do it re ursively?
You would ontra t it to some raftsman. Imagine that the raftsman builds the outer
doll, but does not work on the inner dolls. Instead the task of building the inner k 1 dolls,
whi h is really a k 1 level doll is sub ontra ted to another raftsman. And so it goes.
This ontinues until a raftsman is asked to build a 0 level doll, whi h is just an ordinary
doll. This is not sub ontra ted but built dire tly. So this doll is sent ba k to the previous
raftsman who adds a doll and makes it a level 1 doll and sends it ba k, and so on, until you
eventually re eive the k level doll that you ordered!
This is learly a strange way of building dolls { but what you should understand for
now is that it an work in prin iple. To prove that the pro ess works orre tly, you would
use indu tion. First establish that some raftsman an build a level 0 doll without further
sub ontra ting, the so alled base ase. Next, you must prove that a raftsman an put
together a level i + 1 doll given a level i doll. This is the indu tive step.
We see how this works for GCD next.
10.1.3 Corre tness of re ursive programs
The key to proving the orre tness of re ursive programs is to use mathemati al indu -
tion. We rst need to have a notion of the size of the problem being solved. The indu tion
hypothesis typi ally states that the program orre tly solves problems of a ertain size.
As an example we will see how to argue that our ode will orre tly ompute the GCD.
The argument is really very similar to that in Se tion 7.7, but we will state it more dire tly
this time.
In our ase, it is natural to hoose the value of the se ond argument as the size of the
problem. Our indu tion hypothesis IH (j ) is: g d(i; j ) orre tly omputes the GCD of i; j
for all i.
The base ase is j = 1. But in the rst step of g d(i; 1) we will dis over that i%1 is zero,
and will report 1 as the answer. This is learly orre t.
Abhiram Ranade, 2013. Do not distribute 168

Figure 10.2: An exoti tree


So let us assume IH (1); IH (2); : : : ; IH (j ). Using these we will prove IH (j + 1). So
onsider the all g d(i; j + 1). In the rst step, we he k whether i%(j + 1) equals 0. This
is true if j + 1 divides i, and in that ase j + 1 is the GCD, whi h is orre tly returned.
Suppose then that the ondition is false. In that ase the algorithm tries to ompute and
return g d(j; i%(j + 1)), But the se ond argument in this is the remainder when something
is divided by j + 1, so learly it must be at most j . Thus by one of our assumptions
IH (1); : : : ; IH (j ), we know that this all will return orre tly, i.e. return GCD(j; i%(j +1)).
But by Eu lid's theorem, we know that this is also GCD(i; j +1), i.e. it is the orre t answer.
Thus orre tness follows by the prin iple of (strong) indu tion.
You will observe that this proof is very similar to the proof in Se tion 7.8. Indeed, the
non-re ursive program in that se tion is really doing the same al ulations as the re ursive
one: the values of m,n in the tth iteration will be the same as the values taken by the
arguments m,n in the tth re ursion. Indeed, other assertion made there, e.g. that the
number of iterations must be O(log m), if GCD(m; n) is being al ulated, will orrespond
to the assertion in the present ase that the re ursive program will re urse only to a depth
O(log m). Thus the total time taken will be O(log m) as for the non-re ursive algorithm.

10.2 Re ursive pi tures


Figure 10.2 shows a pi ture whi h we might onsider, using some imagination, to be of a
tree, say from the Afri an Savannas. Our goal in this se tion is to write a program to draw
Abhiram Ranade, 2013. Do not distribute 169

Height h−1 tree Height h−1 tree

Height h tree

Figure 10.3: Re ursive stru ture of our exoti tree


su h trees. Note that our interest in trees goes beyond botany; tree diagrams are used in
many pla es. Thus, a tree might depi t the heirar hi al stru ture of many organization, e.g.
the root might represent the president, and that may be onne ted to the vi e presidents
who report to the president, those in turn to the managers who report to the vi e presidents.
As you will see later, the manner in whi h fun tions are alled also have a tree stru ture. So
understanding tree stru tures and being able to draw them is useful.
Figure 10.2 has some interesting symmetries. First of ourse there is a symmetry of
re e tion about a verti al line through the middle. But also to be noted is the another kind
of symmetry: parts of the tree are similar to the whole. The portion of the tree on top of
the left bran h from the bottom, or the portion on top of the right bran h, an ea h be seen
as a tree. In fa t we might des ribe a tree as two small trees on top of a \V" shape formed
by the bran hes at the bottom.
More formally, it is ustomary to de ne the height of the tree to be the maximum number
of bran hes you travel over as you move up from the root towards the top along any path.
Our tree of Figure 10.2 has height 5. Clearly, we an say that a tree of height h is made up of
a root with two bran hes going out, on top of ea h of whi h sits a height h 1 tree, as shown
in Figure 10.3. Of ourse, to draw the pi ture, we need more information, for example, what
is the length of the bran hes, and what are the angles at whi h the bran hes emerge. For the
tree shown, the bran h lengths shrink as we go upwards, and so do the angles. Suppose we
de lare that we want both the bran h lengths and the angles between emerging bran hes to
both shrink by a xed shrinkage fa tor as we go up. Now, if we are given the length of the
bottom most bran hes, and the height of the tree, we should be able to draw the pi ture.
The ode follows the basi observation: to draw a tree of height h > 0, we must draw the
root and immediate bran hes, and two trees of height h 1 on top. A tree of height h = 0 is
just a point, and so nothing need be drawn. As in any drawing program, we must arefully
write the pre and post onditions for the turtle. So we will require that at the beginning the
turtle be at the root, pointing upwards (pre ondition). After the drawing is nished, we
will ensure that the turtle is again at the root and pointing upwards (post ondition). On e
we x these pre and post onditions, the program writes itself: we merely have to ensure
that we maintain the onditions.
Abhiram Ranade, 2013. Do not distribute 170
The pro ess of drawing is as follows. Clearly, if h = 0, we draw nothing and return.
Otherwise, the gure is drawn in a series of 7 steps.
1. Draw the left bran h. At the start, be ause of the pre ondition, we know that the turtle
is pointing upwards, so it must turn by half the angle that is meant to be between the
bran hes. Then we move forward by the length of the bran h.
2. Draw the left subtree. We rst turn so that the turtle is fa ing the top dire tion,
be ause that is a pre ondition for drawing trees. Then we re urse. We need to all
with height h 1, and the bran h length and angle shrunk by the given shrinkage
value.
3. Go ba k to the root. After drawing the left subtree, its post ondition guarantees
that the turtle will fa e dire tly upwards. To get ba k to the root we must turn and
go ba kwards, whi h is a omplished by giving a negative argument to the forward
ommand.
4. Draw the right bran h. Sin e the turtle is pointing in the dire tion of the left bran h,
we must turn it to the right, and then go forward.
5. Draw the right subtree. This is exa tly as we did the left.
6. Go ba k to the root, as we did after drawing the left subtree.
7. Ensure the post ondition. Finally, we want to honour the post ondition, so we turn
the turtle so that it fa es dire tly upward.
This is expressed as the following program, where we have put omments to indi ate the
orresponden e with the steps des ribed above.
void tree(int height, float length, float angle, float shrinkage)
// pre ondition: turtle is at root, pointing up.
// post ondition: same
{
if(height == 0) return;
// 1. draw the left bran h
left(angle/2);
forward(length);
// 2. draw the left (sub)tree.
right(angle/2);
tree(height-1, length*shrinkage, angle*shrinkage, shrinkage);

// 3. go ba k to the root
left(angle/2);
forward(-length);
// 4. draw the right bran h
right(angle);
forward(length);
Abhiram Ranade, 2013. Do not distribute 171
// 5. draw right (sub)tree.
left(angle/2);
tree(height-1,length*shrinkage, angle*shrinkage, shrinkage);
// 6. go ba k to root
right(angle/2);
forward(-length);
// 7. ensure post ondition
left(angle/2);
}
To all the fun tion, we must supply the arguments, but also ensure the pre ondition. Sin e
we know that at the start the turtle is fa ing right, we must turn it left by 90 degrees so
that it points upwards. So our main program ould be the following.
int main(){
turtlesim();
left(90);

tree(5,120,120,0.68);

wait(5);
}

10.2.1 Trees without using a turtle


It is easier to draw a tree without using a turtle, as we will show next. However, using a
turtle has some advantages, whi h we remark upon at the end.
The basi idea is to use the Line shape from Chapter 5. We draw the bran hes using
this, and then re urse to draw the subtrees. Note that we must now pass the oordinates
of the root as well to ea h all. For variety, we will also draw a tree with a somewhat
di erent layout. Spe i ally, we will draw a tree su h that it o upies a given re tangular
box, with the root appearing at the enter of its base. If the oordinates of the root are
given, then the box is spe i ed by giving its height Hb and width Wb . We will also assume
for simpli ity that the for a tree of height H the points at whi h the bran hes divide are at
heights Hb=H; 2Hb=H; 3Hb=H; : : :. Likewise, when a tree has two subtrees, ea h subtree is
a ommodated in a box of half the width of the original box. The ode an now be written
easily.
void tree(int height, float H_b, float W_b,
float rx, float ry) // oordinates of the root.
{
if(height > 0){
float LSRx = rx-W_b/4; // x oordinate of root of Left subtree.
float RSRx = rx+W_b/4; // x oordinate of root of Right subtree.
float SRy = ry-H_b/height; // y oordinate of roots of subtrees.
Abhiram Ranade, 2013. Do not distribute 172

Figure 10.4: Hilbert spa e lling urves H ; H ; H ; H


1 2 3 4

Line Lbran h(rx, ry, LSRx, SRy); Lbran h.imprint();


Line Rbran h(rx, ry, RSRx, SRy); Rbran h.imprint();

tree(height-1, H_b-H_b/height, W_b/2, LSRx, SRy); // Left Subtree.


tree(height-1, H_b-H_b/height, W_b/2, RSRx, SRy); // Right Subtree.
}
}

This ode is more ompa t, be ause we dont have to worry about managing the post ondi-
tions of the turtle.
However it should be noted that this ode is only useful to grow trees verti ally. Suppose
you want to orient the tree at an angle of 60 degrees to the verti al, then this ode is useless.
However, the turtle based ode an be used, we merely all it after the turtle is oriented at
the required angle. This feature appears useful for drawing many real trees, i.e. the subtrees
of many trees appear grow at an angle to the verti al. As a result, to draw realisti looking
(botani al) trees, it might be more onvenient to use the turtle based ode. See Exer ise 13.
10.2.2 Hilbert spa e lling urve
Figure 10.4 shows urves H ; H ; H and H , left to right. The exer ises ask you to under-
1 2 3 4
stand the re ursive stru ture of the urve, i.e. an you obtain Hi by omposing some Hi 1
urves with some onne ting lines. This will help to write a re ursive fun tion to draw an
arbitrary urve Hn. These urves were invented by the mathemati ian David Hilbert, and
are examples of so alled spa e- lling urves.
Abhiram Ranade, 2013. Do not distribute 173
10.3 Virahanka numbers
Suppose you have an unlimited supply of bri ks of heights 1 and 2. You want to onstru t
a tower of height n. In how many ways an you do this? For example, suppose n = 4. One
possibility is to sta k 4 height 1 bri ks, i.e. the order of heights onsidered top to bottom
is 1,1,1,1. Other orders are 1,1,2, or 1,2,1 or 2,1,1 or 2,2. You an he k by trial and error
that no other orders are possible. Thus if you de ne Vn to be the number of ways in whi h
a tower of height n an be onstru ted, we have demonstrated that V = 5. We would like
4
to write a program that omputes Vn given n.
This problem was solved by Virahanka, an Indian prosodist who lived in the 7th entury.
Virahanka (or quite possibly pre eding prosodists, about whom de nite information is not
known) used the following method to solve the problem, whi h has been redited to Pingala,
who lived around 3rd entury BCE. The rst observation is that the bottom-most bri k is
either of height 1 or height 2. You may think this is rather obvious, but from this it follows:
Number of ways of Number of ways of
Number of ways of building a tower building a tower
Vn = building a tower of = of height n with + of height n with
height n bottom-most bri k bottom-most bri k
of height 1 of height 2.

Virahanka observed that if you sele t the bottom-most bri k to be of height 1, then the
problem of building the rest of the tower is simply the problem of building a height n 1
tower. Thus we have
Number of ways of
building a tower Number of ways of
of height n with = building a tower of = Vn 1

bottom-most bri k height n 1


of size 1
Likewise it also follows that
Number of ways of
building a tower Number of ways of
of height n with = building a tower of = Vn 2
bottom-most bri k height n 2
of height 2
So we have
Vn = Vn + Vn
1 2

What we have written above is an example of a re urren e, an equation whi h re ursively


de nes a sequen e of numbers, V ; V ; : : : in our ase.
1 2
Now we are ready to write a re ursive program. Clearly, in order to solve the problem
of size n, we need a solution to problems of size n 1 and n 2 respe tively. So we have
Abhiram Ranade, 2013. Do not distribute 174
a pro edure for redu ing the size of the problem, what we need is the base ase. Is there a
problem that we an solve easily? Clearly, V = 1, be ause a height 1 tower an be built in
1
only 1 way { by using a single height 1 bri k.
The trouble is, that this single base ase, V = 1 is not enough. We should really ask
1
ourselves: will this allow us to nd V ; V and so on? Clearly, we annot even get V with
2 3 2
just this information. However, we an try to nd V dire tly, learly, there are only 2 ways:
2
1,1 and 2. So V = 2. But now, as we keep re ursing, the pairs of numbers we are asking
2
for redu e by one, so eventually the we will want the pair 2,1. But we know the values of V 2
and V , and so the re ursion will indeed terminate. The program is then immediate.
1

int Virahanka(int n){


if(n == 1) return 1; // V_1
if(n == 2) return 2; // V_2
return Virahanka(n-1) + Virahanka(n-2); // V_{n-1} + V_{n-2}
}
If you run this, you will see that it is very slow, even for modestly large n. The reason for
it an be seen in Figure 10.5. This gure shows the so alled exe ution tree for the all
Virahanka(6). Note that we have drawn this tree growing downward, as is more ustomary.
The root is drawn at the top and is marked 6. The root has two bran hes whi h are drawn
downward. There is further bran hing too, however in some pla es the bran hing appears
to have stopped prematurely. We will see how to interpret all this next.
It is worth introdu ing two terms. What we have been alling a bran h, is more te hni ally
alled an edge. The points where the edges terminate, are alled verti es. Thus the root
is a vertex, and there are several others.
In an exe ution tree, the root vertex orresponds to the original all. So we have marked
the root in the pi ture with the argument, 6, to the original all. Out of ea h vertex we have
one downward going edge for every all made. Sin e Virahanka(6) requires Virahanka to
be alled rst with argument 5, and then with 4, we have 2 outgoing bran hes. At the ends
of the orresponding bran hes we have put down 5 and 4 respe tively, the arguments for
the orresponding alls. This goes on till we get to alls Virahanka(2) or Virahanka(1).
Sin e these alls do not make further re ursive alls, there are no outgoing bran hes from
the verti es orresponding to these alls.
As you an see in the gure, Virahanka(4) is alled twi e, on e as a part of Virahanka(5),
and on e dire tly from Virahanka(6). But on e we know V using any all to Virahanka(4)
4
subsequent alls are not really ne essary if we an just remember this value. In fa t, you will
see that the all Virahanka(3) happens 3 times, the all Virahanka(2) happens 5 times,
and the all Virahanka(1) happens 8 times. So the program is quite wasteful. In general, for
large n, you an argue (Exer ise 6) that while omputing Vn, our fun tion will make at least
2bn= alls to Virahanka. Thus if you want to ompute Vn by using the re ursive algorithm
2

you are expe ting to spend time proportional to at least 2n= . This is a huge number, and
2

indeed omputing something like say V using the all Virahanka(45) takes an enormous
45
amount of time on most omputers.
Abhiram Ranade, 2013. Do not distribute 175
6

5
4

3 3
4 2

3
2 2 1 2 1

2 1

Figure 10.5: Exe ution tree for Virahanka(6)

10.3.1 Using a loop


Here is a di erent way to ompute Vn. We know that V = 1, V = 2 and V = V + V . Thus,
1 2 3 1 2
we an ompute V = V +V = 2+1 = 3. After that we an ompute V = V +V = 3+2 = 5.
3 2 1 4 3 2
After that we an ompute V , and this pro ess an go on. Clearly, there is something
5
repetitive going on here. So presumably a loop will be useful to program it. Presumably, we
an ompute one Virahanka number in ea h iteration, and there need to be n 2 iterations,
be ause V ; V were omputed before entering the loop.
1 2
To al ulate a number in the urrent iteration, we need to add the numbers al ulated
in the last iteration, and the se ond last iteration, as shown in Figure 10.6. The key point,
however, is that what is \last" in one iteration, e.g. Figure 10.6(a) is alled \se ond last" in
the next iteration, Figure 10.6(b). Similarly, the \ urrent" of Figure 10.6(a) be omes \last"
of Figure 10.6(b). We have to keep this in mind while writing the ode.
In the ode, we will have variables se ondlast, last, whi h we will assume already have
values, and whi h we will add to produ e a value whi h will be pla ed in a variable urrent.
To go to the next iteration, as shown in Figure 10.6 our notion of what is last and se ond
last must hange. So a ordingly we hange their values. This is the body of the loop, whi h
must be exe uted n 2 times. So here is the fun tion.
int VirahankaByLooping(int n){ // Program to ompute Virahanka number V_n
int v1=1,v2=2; // v1 = V_1, v2 = V_2
if(n == 1) return v1;
else if(n == 2) return v2;
else {
int se ondlast=v1, last=v2, urrent;
repeat(n-2){
urrent = se ondlast + last;

se ondlast = last; // prepare for next iteration


last = urrent;
Abhiram Ranade, 2013. Do not distribute 176

V1 = 1 V2 = 2 V3 = 3 V4
se ond last last urrent

(a)

V1 = 1 V2 = 2 V3 = 3 V4 = 5 V5

se ond last last urrent

(b)

Figure 10.6: Computing Virahanka Numbers


Abhiram Ranade, 2013. Do not distribute 177
}
return urrent;
}
}
The important point to note in this ode is the preparation of the variables se ondlast and
last for the next iteration. This also stresses the important point that we should onsider
ea h variable as performing a ertain fun tion, e.g. holding the last omputed Virahanka
number, and the value of the variable must be hanged to re e t its fun tion.
To ompute Vn, this fun tion will require n 2 iterations. Ea h iteration takes a xed
amount of time independent of n. Thus we an say that the total time is approximately
proportional to n.
Indeed, you will see that V gets omputed essentially instantaneously using this loop
45
based fun tion.
10.3.2 Histori al Remarks
Virahanka a tually onsidered a di erent problem. He was onsidering di erent ways of on-
stru ting poeti meters, built using syllables of length 1 and length 2. The length of a poeti
meter is simply the sum of the lengths of the syllables in the meter. The question he asked
was: how many di erent poeti meters an you ompose of a given length? Mathemati ally,
it is the same problem as we solved.
This sequen e should look familiar to many readers. Indeed, these numbers are more
ommonly known as the Fibona i numbers. But Virahanka is known to have studied them
before Fibona i. In fa t it appears that they may have been known in India even before
Virahanka. In any ase, it seems more appropriate to all these numbers Virahanka numbers
rather than Fibona i numbers.

10.4 The game of Nim


In this we will write a program to play the game of Nim. This game is quite simple, but
nevertheless interesting, and our program will ontain a key idea whi h will be useful in all
game playing programs.
The game has two players, say White and Bla k. There are some n piles of stones, the
ith pile ontaining xi stones at the beginning. We will have di erent games for di erent
hoi es of xi. A move for a player involves the player pi king a pile in whi h there is at least
one stone, and removing one or more stones from that pile. The players move alternately,
say with White moving rst. The player that makes the last valid move, i.e. after whi h no
stones are left, is onsidered the winner. Or you may say that the player who is unable to
make a move on his turn be ause there are no stones left is the loser.
Here is a simple example. Suppose we have only 2 piles initially with 5 and 3 stones
respe tively. Suppose White pi ks 4 stones from pile 1. Then the rst pile has 1 stone left
and the se ond has 3. Now Bla k an win by pi king 2 from the se ond pile: this will leave
1 stone in ea h pile, and then White an pi k only 1 of them, leaving the last one for Bla k.
Of ourse, White need not have pi ked 4 stones in the very rst move. Is there a di erent
Abhiram Ranade, 2013. Do not distribute 178
hoi e for whi h he an ensure a win? We will leave it to you to observe that White an in
fa t win this game by pi king only 2 stones from the rst pile in his rst move.
So here is the entral question of this se tion: Given the game position, i.e. number
of stones in ea h pile, determine whether the player whose turn it is to play an win, no
matter what the other player plays. In ase the position is winning, we would also like to
determine a winning move. Note by the way, that when we say winning/losing position, we
mean winning/losing for the player whose turn it is to move.
In trying to solve any problem, it is a good idea to try out some examples rst. Consider
the simplest possible position: the position in whi h no pile ontains any stone be ause all
were taken earlier. As de ned above, in this position, the player whose turn it is is learly
the loser. The next harder example is: suppose there is only one pile with just one stone.
Clearly, this is a winning position (for the player on move) be ause he an take that stone.
In fa t, if there is just one pile with any number of stones, it is a winning position be ause
the player on move will take the entire pile.
Let us next onsider the next more omplex situation, say there are 2 piles, ea h with
one stone. There are only two (similar) moves possible, either take the stone in the rst pile,
or the stone in the se ond pile. In either ase, we leave behind a single pile with 1 stone,
whi h is a winning position for our opponent. Thus, an important prin iple emerges from
this example:
Observation 1: If from a ertain position P , suppose on every move we go to a
winning position. Then P is a losing position.
This is indeed an important observation. Let us keep going and onsider more omplex
situations, say there are two piles, in the rst one there are 2 stones, and the se ond has
only one. Now we have a hoi e of 3 moves:
1. Pi k one stone from the rst pile. In that ase, one stone remains in ea h pile. As we
have dis ussed, this is a lost position for our opponent. So good for us!
2. Pi k two stones from the rst pile. In this ase, we leave just one stone. This is a
winning position, for our opponent. Hen e not good for us.
3. Pi k the only stone from the se ond pile. This leaves behind one pile with two stones.
As dis ussed above, this is also a winning position, for our opponent. Hen e this is not
good either.
So in this position, the rst move will make us win while the remaining two will make us
lose. So what do we make of this position? Remember that we have the hoi e of what move
to make, and hen e we will ertainly hoose the rst move! So this position is a winning
position for us. This seems to generalize into another observation.
Observation 2: If in some position P there exists a move after whi h we rea h a
losing position. Then P is a winning position.
Note that this observation ni ely omplements the rst one. If we nd that some move leads
to a losing position, then the se ond observation applies. If we nd that there is no su h
move, i.e. all moves lead to a winning position, then the rst observation applies.
Abhiram Ranade, 2013. Do not distribute 179
The above observations gives us a re ursive algorithm for determining if a given position
P is winning or losing. We determine all moves mi possible in P , and the positions Pi they
lead to. The we determine (re ursively!) whether Pi are winning or losing. If we nd some
Pi that is losing, we de lare P to be winning. Otherwise if all Pi are winning, we de lare P
to be losing. We know that in order for a re ursive algorithm to work we must ensure that
two things:
1. Ea h subproblem we are required to solve is simpler than the original. In our ase this
is true in the sense that ea h Pi must have at least one stone less than P , and is hen e
simpler.
2. We an argue that eventually we will rea h some (\simplest") problems whi h we an
solve dire tly. Clearly, as the game progresses we will rea h the situation in whi h no
stone remains. As dis ussed, this is a losing position.
Thus we an write a program to determine whether a Nim position is winning or losing. We
give this program for the ase of 3 piles, but you an see that it an be easily extended for a
larger number of piles. The fun tion winning given below takes a game position and returns
true if the position is winning, and false if the position is losing.

bool winning(int x, int y, int z)


// x,y,z = number of stones in the 3 piles.
// returns true if this is a winning position.
{
if(x==0 && y==0 && z==0) return false; // base ase

for(int i=1; i<=x; ++i) // Pi k i stones from pile 1


if (!winning(x-i,y,z)) return true; // if a losing next state is found

for(int i=1; i<=y; ++i) // Pi k i stones from pile 2


if (!winning(x,y-i,z)) return true; // if a losing next state is found

for(int i=1; i<=z; ++i) // Pi k i stones from pile 3


if (!winning(x,y,z-i)) return true; // if a losing next state is found

return false; // if all next states are winning


}

The fun tion an be alled using a main program su h as the one below.
int main(){
int x,y,z;
out << ``Give the number of stones in the 3 piles: ``;
in >> x >> y >> z;
if (winning(x,y,z)) out << ``Wins.'' << endl;
else out << ``Loses.''<<endl;
}
Abhiram Ranade, 2013. Do not distribute 180
Our fun tion only says whether the given position is winning or losing, it does not say what
move to play if it is a winning position. You an easily modify the program to do this, as
you are asked in the exer ises.
The logi of our fun tion should be lear. In the given position, we an hoose to take
stones from either the rst pile, the se ond pile, or the third pile. The rst loop in the
fun tion onsiders in turn the ase in whi h we remove i stones from the rst pile. This
leaves the new position in whi h the number of stones is x-i,y,z. We re ursively he k if
this is a losing position. If so, the original position, i.e. in whi h there are x,y,z stones
respe tively, must be a winning position by observation 2. The subsequent loops onsider the
ases in whi h we remove stones from the se ond and third piles. If we nd no losing position
after he king all moves, then indeed the original position must be losing, by observation 1.
So we return false in the last statement of the fun tion.
10.4.1 Remarks
It turns out that there is a more dire t way to say whether a given position is winning or
losing. This is very lever, involving writing the number of stones in the piles in binary, and
performing additions of the bits modulo 2 and so on. We will not over this, but you should
be able to nd it dis ussed on the internet.
Our program is nevertheless interesting, be ause the general stru ture of the program
applies for many 2 player games. Indeed, re ursion is an important tool in writing game
playing programs.

10.5 Con luding remarks


A number of points need to be noted.
The most important idea in this hapter on erns algorithm design. Suppose you want
to solve an instan e of a ertain problem. Then it helps to assume that you an solve smaller
instan es somehow, and ask: will the solution of smaller instan es help me in solving the
larger instan e. It is possible that Eu lid dis overed his GCD algorithm thinking in this
manner. Virahanka probably also dis overed the solution to his problem thinking in this
manner.
In addition to having re ursive algorithms, we also have re ursive stru tures. Trees are a
good example of obje ts with a re ursive stru tures. We an exploit the re ursive stru ture
to design a re ursive algorithm for drawing trees. But as you will see later, trees will be used
for representing many familiar obje ts, and in fa t designing algorithms for those obje ts
will require exploiting the re ursive stru ture.
The notion of re urren es is also important.
The example of Virahanka numbers also demonstrates an interesting point. It is quite
likely that Virahanka also solved his problem by thinking re ursively, and indeed it is a good
idea to think re ursively for the purpose of solving problems. But we must remember that
sometimes it may not be best to write the program re ursively.
Finally, a te hni al point should be noted regarding the al ulation of Virahanka numbers.
As you will show in the exer ises, Vn is at least 2n= , and hen e even for modest value of n
2

it will not t in an int. If you use long long you an work with somewhat larger values.
Abhiram Ranade, 2013. Do not distribute 181
If you use double you an work with mu h larger values of n, but they will be orre t only
to 15 digits or so.

Exer ises
1. The fa torial of a number n is denoted as n!, and an be de ned using the re urren e
n! = (n 1)! for n > 0 and 0! = 1. Write a re ursive fun tion to ompute n!.
   
2. The binomial oeÆ ient
 
n
r
an be de ned re ursively as n
r
= n1
r 
+ n
r
, for 1

n; r > 0 and = n = 1 for all n  0. Write a fun tion to ompute r .


1
n n n
0

3. Consider an equation ax + by = , where a; b; are integers, and the unknowns x; y are


required to be integers. Su h equations are alled Diaphontine equations. If GCD(a; b)
does not divide , then the equation does not have any solution. However, the equation
will have in nitely many solutions if GCD(a; b) does divide . Write a program whi h
takes a; b; as input and prints a solution if GCD(a; b) divides .
Hint 1: Suppose a = 1. Show that in this ase an integer solution is easily obtained.
Hint 2: Suppose the equation is 17x + 10y = 4. Suppose you substitute y = z x.
Then you get the new equation 7x + 10z = 4. Observe that the new equation has
smaller oeÆ ients, and given a solution to the new equation you an get a solution to
the old one.
4. Dedu e the general stru ture of Hilbert spa e lling urves by observing Figure 10.4.
Draw a pi ture (on paper) showing how Hn is omposed of one or more Hn urves. 1
This should be in the style of Figure 10.3. Write a turtle based program to draw a
Hilbert spa e lling urve Hn given n.
Follow the general s heme we used in Se tion 10.2, i.e. begin by stating the pre and
post onditions for the turtle for drawing Hn. Try to draw the urve without lifting
the pen or overdrawing.
You may nd the following fa t useful. Suppose a ertain fun tion f draws some gure
F. Then if we repla e every turning angle  in f by , then we will get a gure that
is a mirror image of F.
5. Consider the re urren e Wn = Wn + Wn + Wn , with W = W = W = 1. Write
1 2 3 0 1 2
a re ursive program for printing Wn. Also write a loop based program.
6. Let Bn denote the number of bran hes in the re ursion tree for Vn. Thus B = 14, 6
onsidering Figure 10.5. Note that ea h bran h ends in a all to Virahanka, hen e Bn
gives a good estimate of the number of operations needed to ompute Vn. (a) Write a
re urren e for Bn and use it to write a program that omputes Bn. What are the base
ases for this? Make sure your answer mat hes the bran hes in the trees of Figure 10.5.
(b) Argue using indu tion that Bn  2bn= for n  3.
2

7. Prove using indu tion that 2bn=  Vn  2n. Based on this what data type would you
2

use for omputing V ? If it helps you may note the stonger result Vn  1:62n  2n= : .
80
1 43
Abhiram Ranade, 2013. Do not distribute 182
8. Suppose you all the fun tion g d on onse utive Virahanka numbers Vn; Vn . There
+1
is something interesting about the arguments to the su essive re ursive alls. What is
it? The depth of the re ursion is de ned to be the number of onse utive re ursive alls
made, ea h nested inside the pre eding one. What is the depth of the re ursion for the
all g d(Vn ; Vn)? Based on this, argue that the time taken by g d when alled on n
+1
bit numbers ould be as large as n=2.
9. Consider the g d fun tion developed in the hapter. Suppose the initial all is with
arguments m ; n and su essive alls are made with arguments m ; n , then m ; n ,
0 0 1 1 2 2
then m ; n and so on. Show that ni  ni . Based on this argue that a all to g d
3 3 +2
with n bit numbers will have depth of re ursion at most 2n. In other words, the time
to ompute the g d will be at most proprortional to the number of bits in the numbers.
10. Consider a omplete binary tree with height h. As you an see, su h a tree has 2h 1+1

verti es. Our goal now is to write a program that not only draws su h a tree, but also
assigns a unique number for ea h vertex, in the range 1 through 2h 1. Further, the
+1

number should be printed in the pi ture, slightly to the right of the vertex itself. The
simplest numbering is the In-order numbering. In this the verti es are numbered 1
through 2h 1 in left to right order. Thus the leftmost leaf would get the number 1,
+1

the root of the entire tree would get the number 2h, and the rightmost leaf would get
the number 2h 1. You are to modify our program drawing trees without using the
+1

turtle so that this numbering is also printed. Hint: It might be useful have a referen e
argument to the fun tion tree that somehow an be used to de ide the number of a
node.
11. Another interesting numbering of tree nodes is the Pre-order numbering. The pre-
order time of a node is simply the time at whi h the subtree rooted at that node starts
getting drawn. Based on this, the pre-order number of a node is de ned to be i if its
preorder time is the ith smallest.
Modify our tree drawing program (not using turtle) so that it prints the pre-order
numbers along with the tree. As examples, note that the root has pre-order number
1, the leftmost leaf the number h + 1, and the rightmost leaf the number 2h 1.
+1

12. Another interesting numbering of tree nodes is the Post-order numbering. The post-
order time of a node is simply the time at whi h drawing of the subtree rooted at that
node is nished. Based on this, the post-order number of a node is de ned to be i if
its post-order time is the ith smallest.
Modify our tree drawing program (not using turtle) so that it prints the post-order
numbers along with the tree. As examples, note that the leftmost leaf has post-order
number 1, the root the number 2h 1, and the rightmost leaf the number 2h h 1.
+1 +1

13. More ommonly, (botani al) trees have a single trunk that rises verti ally, and then
splits into bran hes. So you ould onsider a tree to be \one verti al bran h, with two
trees growing out of it at an angle". Draw trees expressing this idea as a re ursive
program. It will be onvenient to use the turtle for this. Try out variations, nd whi h
trees look realisti . .
Abhiram Ranade, 2013. Do not distribute 183
14. Write a fun tion draw Hem that draws the re ursion tree for alls to Virahanka, i.e.
draw Hem(6) should be able to onstru t the tree shown in Figure 10.5.

15. The tree drawn in Figure 10.2 is alled a omplete binary tree. Binary, be ause at
ea h bran hing point there are exa tly 2 bran hes, or at the top, where they are no
bran hes. Complete, be ause all bran hes go to the same height. You ould have an
in omplete binary tree also, say you only have one bran h on one side and the entire
tree on the other.
Write a program whi h takes inputs from the user and draws any binary tree. Suppose
to any request the user will only answer 0 (false) or (true). Devi e a system of questions
using whi h you an determine how to move the turtle. Make sure you ask as few
questions as possible.
16. Consider the points (i; j ) where 0  i; j < n for some onstant n, say n = 10. We want
to walk from (0; 0) to (n 1; n 1) taking exa tly n 1 unit steps in the positive x
dire tion, and exa tly n 1 unit steps in the positive y dire tion. It is a eptable to
take order the steps in the x and y dire tion as we wish, i.e. we may alternate them
or take all x steps rst and so on. We must take a total of 2n 2 steps, of whi h n 1
must be along the x dire tion. Thus the total number ofn ways  of hoosing, whi h is
also the number of distin t paths that we an follow, is n . With ea h path we an
2 2

asso iate a 2n 2 bit number, whose j th least signi ant bit is 0 if the j th step on the
1

path is in the x dire tion, and 1 if the j th step is in the y dire tion.
Write a program that takes as input integers n; p and prints out the pth largest number
in the set of all paths. Hint: How many paths will have a 0 in the most signi ant bit?
17. Suppose you want to send a message using the following very simple ode. Say your
message only onsists of the letters 'a' through 'z', and in the ode your merely repla e
the ith letter by i. Thus 'a' will be oded as 1, 'b' as 2, and so on till 'z' by 26. Further,
there are no separators between the numbers orresponding to ea h letter. Thus, the
word \bat" will be oded as the string 2120. Clearly, some strings will have more than
one interpretation, i.e. the string 2120 ould also have ome from \ut". Suppose you
are given a string of numbers, say 1 digit per line (so 2120 will be given on 4 lines).
You are to write a program that takes su h a sequen e of numbers and prints out the
number of ways in whi h it an be interpreted. You are free to demand that the input
be given from the last digit if you wish.
18. There are many variations possible on the game of Nim as des ribed above. One
variation is: the player who moves last loses. How will you determine whether a
position is winning or losing for this new game?
19. In another variation, you are allowed to pi k either any non-zero number of stones from
a single pile, or an equal number of stones from two piles. Write a fun tion that says
whether a position is winning for this game.
20. Write a fun tion whi h returns a 0 if the given position is losing, but if the position
is winning, returns a value that somehow indi ates what move to make. De ide on a
Abhiram Ranade, 2013. Do not distribute 184
suitable en oding to do this. For example, to indi ate that s stones should be pi ked
from pile p, return the number p  10m + s, where 10m is a power of 10 larger than
x; y; z the number of stones in the piles for the given position. With this en oding, the
last m digits will give the number of stones to pi k, and the more signi ant digits will
indi ate the pile number. Some of you might wonder whether we an return pairs of
numbers out of a fun tion (without having to en ode them as above) { we will see how
to do it later in the book.
21. Write a re ursive fun tion for nding xn where n is an integer. Try to get an algorithm
whi h requires far fewer than the n 1 multipli ations needed in the natural algorithm
of multiplying x with itself. Hint: Show that k multipli ations suÆ e if n = 2k for
some integer k. Then build up on this.
Chapter 11

Program organization and fun tions

We dis ussed fun tions as a way of en apsulating frequently used ode so that it an be
written just on e and then alled whenever needed. However, fun tions also play another
role in C++ programs. Just as a ell is a basi physiologi al and stru tural unit of life, a
fun tion an be onsidered to be an organizational unit of C++ programs. A C++ program
essentially is a olle tion of fun tions . As we will see shortly, even the main program you
1

have been writing is turned into a fun tion by simple pp, stru turally similar to the other
fun tions we have been writing. Managing the fun tions onstituting a program, espe ially
large programs, requires a systemati approa h. The problem is further ompli ated be ause
large programs are often developed by teams of programmers, with ea h programmer possibly
responsible for developing some of the fun tions. Clearly, it is onvenient if the di erent
fun tions needed for a program are in di erent les. In this hapter, we will see some of the
issues in breaking up a program into fun tions, possibly spread over multiple les, but yet
able to all ea h other and work together as a single program.
One important hallenge is the management of names. A name is not useful if there is
any ambiguity as to what exa tly it refers to. On the other hand, if a program is written
ooperatively, there is a han e that di erent programmers might use the same name to
de ne a fun tion that they wrote. Or it might be that you are borrowing a pa kage (su h as
simple pp) written by someone else and using it in your program. E e tively, this also sets
up the possibility of a name lash: how do you ensure that you dont use the same name that
is used in the pa kage that you borrowed? Or if you do use it, will it ause any ambiguity?
These are some of the issues dis ussed in this hapter.
We begin by showing how simple pp turns the main program that you write into a
fun tion as required by C++. After that we will see the rules for breaking up a program
into multiple les, or alternatively, for assembling a program given a set of fun tions spread
over several les. As mentioned above, an important issue will be management of names.
The notion of de larations will be useful in this. Another useful notion will be that of a
namespa e, whi h we will also study.
We mentioned in the introdu tion that simple pp hides some of the te hni ally advan ed
features of C++ so as to make it easier for a beginner to get to the heart of our subje t: how
to write programs. But this hapter will have introdu ed you to all the te hni al features
hidden by simple pp. Thus by the end of the hapter, you will be able to use C++ dire tly,
1 We will amend this statement a bit later

185
Abhiram Ranade, 2013. Do not distribute 186
if you so hoose, without having to in lude simple pp in your programs. We will dis uss
this in Se tion 11.6.
We will end by making some philosophi al remarks on how to break a program into
fun tions.

11.1 The main program is a fun tion!


C++ in fa t requires that the main program be written as the body of a fun tion alled
main, whi h takes no arguments and returns an integer value. We did not tell you all this
at the beginning of the book be ause at that time you did not know about fun tions, and
it might have been too overwhelming to nd out. So instead, we asked you to write the
main program in a blo k following the name main program. Our pa kage simple pp uses
the prepro essor fa ility (Appendix G) of C++ to hange the name main program that you
write into the phrase int main(). Thus what you spe ify as the main program be omes the
body of a fun tion alled main as required.
When a C++ program is ompiled and run, the operating system expe ts that there be
a fun tion in it alled main. Running a program really means alling the fun tion main. The
main fun tion has return type int be ause of some histori al reasons not worth understand-
ing. You may also be wondering why we havent been writing a return statement inside
main if in fa t it is supposed to return an int. The C++ ompiler we have been using, the
GNU C++ ompiler, ignores this transgression, that's why!
Now that you know that the main program is just another fun tion, from now on we
will drop the name main program and start writing the main program as a fun tion named
main. So should you.

11.2 Organizing fun tions into les


It is possible to pla e the main program and the other fun tions in di erent les if we wish.
If a program is very large, breaking it up into multiple les makes it easier to manage. A
program an be partitioned into a olle tion of les provided the following rules are obeyed.
Rule 1: If a ertain fun tion f is being alled by the ode in le F, then the fun tion f
must be de lared inside F, textually before the all to f. Note that a fun tion de nition
is a de laration, but not vi e versa. We will see what a de laration is shortly.
Rule 2: Every fun tion that is alled must be de ned exa tly on e in some le in the
olle tion.
On e you have a olle tion of les satisfying the above rules, they an be ompiled into a
program provided they ontain a fun tion main. We will see this with an example shortly.
11.2.1 Fun tion De laration or Prototype
The de laration of a fun tion states the name of the fun tion, its return type, and the types
of its arguments. Indeed, a fun tion de laration an be spe i ed by giving its de nition
without the body. Here for example are the de larations of l m and g d.
Abhiram Ranade, 2013. Do not distribute 187
int l m(int m, int n);
int g d(int m, int n);

The names of the parameters an be omitted from de larations, e.g. you may write just
int l m(int,int); in the de laration. The de laration is also alled a prototype, or even a
signature.
Suppose a ompiler is pro essing a le ontaining the statement out << l m(24,36);.
When it rea hes this statement, it needs to be sure that l m is indeed a fun tion, and not some
typing mistake. It also needs to know the type of the value returned by l m { depending upon
the type the printing will happen di erently. Both these needs are met by the de laration.
A de laration of a fun tion f provides (a) an assuran e that f as used later in the program
is indeed a fun tion, and that in ase it has not been de ned so far, it will be de ned later
in this le itself or in some other le, (b) a des ription of the types of the parameters to the
fun tion and the type of the value returned by the fun tion. Given the de laration, the le
an be ompiled ex ept for the ode for exe uting the fun tion itself, whi h an be supplied
later (Se tion 11.2.3). Noti e that a fun tion de nition also provides the information in (a),
(b) mentioned above, and hen e is a also onsidered to be a de laration.
11.2.2 Splitting a program into multiple les
Using the notion of a de laration, we an break up programs into multiple les. As an
example, onsider the main program of Se tion 9.2 that alls our fun tion l m to nd the
LCM of 36 and 24. Thus there are 3 fun tions in our program overall: the fun tion main,
the fun tion l m and the fun tion g d. Figure 11.1 shows how we ould form 3 les for the
program.
First onsider the le g d. pp, whi h ontains the fun tion g d. It does not all any
other fun tion, and so does not need to have any additional de laration. Next onsider the
le l m. pp. This ontains the fun tion l m whi h ontains a all to g d. So this le has
a de laration of g d at the very beginning. Finally the le main. pp ontains the main
program. This alls the fun tion l m, so it ontains a de laration of l m at the beginning.
Note that the main program uses the identi er out to write to the onsole. For this it
needs to in lude simple pp. The other les do not ontain anything whi h needs servi es
from simple pp, so those do not have the line #in lude <simple pp> at the top.
There are various ways in whi h we an ompile this program. The simplest possibility
is to issue the ommand
s++ main. pp l m. pp g d. pp
This will produ e an exe utable le whi h will indeed nd the LCM of 36,24 when run.
11.2.3 Separate ompilation and obje t modules
But there are other ways of ompiling as well. We an separately ompile ea h le. Sin e ea h
le does not ontain the omplete program by itself, an exe utable le annot be produ ed.
What the ompiler will produ e is alled an obje t module, and this an be produ ed by
issuing the ommand
Abhiram Ranade, 2013. Do not distribute 188

//-----------------------------------------------------------------
int g d(int m, int n){
int mdash,ndash;

while(m % n != 0){
mdash = n;
ndash = m % n;
m = mdash;
n = ndash;
}
return n;
}
//-----------------------------------------------------------------

(a) The le g d. pp
//-----------------------------------------------------------------
int g d(int, int); // de laration of fun tion g d.

int l m(int m, int n){


return m*n/g d(m,n);
}
//-----------------------------------------------------------------

(b) The le l m. pp
//-----------------------------------------------------------------
#in lude <simple pp>
int l m(int m, int n); // de laration of fun tion l m.

int main(){
out << l m(36,24) << endl;
}
//-----------------------------------------------------------------

( ) The le main. pp
Figure 11.1: The les in the program to nd LCM
Abhiram Ranade, 2013. Do not distribute 189
s++ - filename
The option - tells the ompiler to produ e an obje t module and not an exe utable. Here
filename should be the name of a le, say main. pp. In this ase, an obje t module of
name main.o is produ ed. If di erent programmers are working on di erent les, they an
ompile their les separately giving the - option, and they will at least know if there are
ompilation errors.
We an form the exe utable le from the obje t modules by issuing the ommand s++
followed by the names of the obje t modules. Thus for our example we ould write:
s++ main.o g d.o l m.o
This use of s++ is said to link the obje t modules together. The linking pro ess will he k
that every fun tion that was de lared in a module being linked is de ned either in the same
module or in one of the other modules being linked. After this he k, the ode in the di erent
modules is stit hed up to form the exe utable le.
It is a eptable to mix . pp les and .o les as arguments to s++, e.g. we ould have
issued the ommand
s++ main. pp g d.o l m.o
This would ompile main. pp and then link it with the other les. The result main.o of
ompiling will generally not be seen, be ause the ompiler will delete it after it is used for
produ ing the exe utable.
11.2.4 Header les
Suppose programmers M; G; L respe tively develop the fun tions main, g d, l m. Then G
has to tell L how to de lare the fun tion g d in the le l m. pp. The most natural way
of onveying this information is to write it down in a so alled header file. A header le
has a suÆx .h, or a suÆx .hpp or no suÆx at all, like our le simple pp, whi h is also a
header le. A simple strategy is to have a header le F.h for every program le F. pp whi h
ontains fun tions used in other les. The le F.h merely ontains the de larations of all the
fun tions in F. pp that are useful to other les. Thus we might have les g d.h ontaining
just the line int g d(int,int), and l m.h ontaining the line int l m(int,int). Now
the programmer L writing the fun tion l m an read the le g d.h and put that line into
l m. pp. However, it is less errorprone and hen e more ustomary that M will merely pla e
the in lusion dire tive
#in lude "l m.h"
in his le instead of the de laration. This dire tive auses the ontents of the mentioned
le, (l m.h in this ase) to be pla ed at the position where the in lusion dire tive appears.
The mentioned le must be present in the urrent dire tory (or a path ould be given). 2

The name of the le must typi ally be given in quotation marks if the le is present in the urrent
2
dire tory or at a pla e given using an expli it path. If the le is present in some dire tory that the ompiler
is asked to look into using some other me hanisms, then angled bra es are used, e.g. #in lude <simple pp>.
To get the exa t details you will need to onsult the do umentation of your ompiler/linker.
Abhiram Ranade, 2013. Do not distribute 190
Thus all that is needed in addition is to pla e the le l m.h also in the dire tory ontaining
main. pp. Likewise M will pla e the line #in lude "l m.h" in main. pp, as a result of
whi h the de laration for l m would get inserted into the le main. pp as needed.
Note that we ould have used a single header le, say g dl m.h ontaining both de la-
rations.
int g d(int,int);
int l m(int,int);
We ould in lude this single le in main. pp and l m. pp. This will ause both de larations
to be inserted into ea h le, while only one is needed. Having extra de larations is a eptable.
11.2.5 Header guards
Header les an be ome quite involved. If there are several header les, then you an pla e
the in lusion dire tives themselves in another header le. In luding the latter le will ause
the former les to be in luded. If we have header les in luded inside one another, it raises
the following possibility: we in lude some le a.h whi h in turn in ludes les b.h and .h,
both of whi h in lude the le d.h. This an ause a problem be ause as per our urrent
de nition of header les, whatever is in d.h will get in luded, and hen e de ned twi e.
De laring the same name again is of ourse an error.
So what we need is a way to say, \in lude what follows only if it has not been in luded
earlier".
This is what header guards provide. Indeed, it is more ustomary to write the header
le g dl m.h in the following form.
#ifndef GCDLCM_H
#define GCDLCM_H
int g d(int,int);
int l m(int,int);
#endif
The rst line he ks if a so alled prepro essor (Appendix G) variable GCDLCM H has already
been de ned. Only if it is not de ned, then the rest le, till the line #endif is pro essed.
Noti e that the se ond line, should it be pro essed, will de ne GCDLCM H. This will ensure
that subsequent in lusions of the le g dl m.h will have no e e t.
Note that prepro essor variables, unlike C++ variables, an be de ned without being
assigned a value, as in the ode above. Also note that the name of the variable an be
anything of your hoosing; using the apitalized name of the le with a suÆx H is just a
onvention.
11.2.6 Pa kaging software
The above dis ussion shows how you ould develop fun tions and supply them to others.
You reate a F. pp le and the F.h le ontaining de larations of the fun tions de ned in
F. pp. Next you ompile the F. pp le giving the - option. Then you supply the resulting
F.o le and the F.h le to whoever wants to use your fun tions. They must pla e the le
Abhiram Ranade, 2013. Do not distribute 191
F.h in the dire tory ontaining their sour e les (i.e. les ontaining their C++ programs),
and pla e the line #in lude "F.h" in the les whi h need the fun tions de lared in F.h.
Next, they must mention the le F.o while ompiling, giving the pathname in ase it is not
in the urrent dire tory. Note that other programmers do not need to see your sour e le
F. pp if you dont wish to show it to them.

11.2.7 Forward de laration


Let us go ba k to the ase in whi h all fun tions are in a single le. We suggested in
Se tion 9.1 that a fun tion must be de ned before its use (i.e. the all to it) in the le.
However, as we dis ussed in the beginning of Se tion 11.2, it suÆ es to have a de laration
before the use. So if we wish to put the fun tion de nition later, we must additionally pla e
a de laration earlier.
When writing a program with several fun tions in a single le, many people like to pla e
the main program rst, perhaps be ause it gives a good overview of what the entire program
is all about. We an do this; it is ne to organize the ontents of your le in the following
order.
de larations of fun tions in any order.
definition of main
definitions of other fun tions in any order.

Of ourse, other orders are also possible.


11.2.8 Fun tion templates and header les
A fun tion template must be present in every sour e le in whi h a fun tion needs to be
reated from the template. So a template is best written in a header le. Note that the tem-
plate itself annot be ompiled; only the fun tion generated from the template is ompiled.
So for a template fun tion f we will typi ally have a header le f.h, but no le f. pp.

11.3 Namespa es
We next onsider an important question whi h typi ally arises when a program makes use of
fun tions developed by di erent people, developed possibly at di erent times. The question
is: what happens if you borrow ode from two programmers, both of whom have de ned a
fun tion with the same name and the same signature? Note that you may not get the sour e
ode for the fun tions, and hen e there may be no way of hanging the name of any of the
fun tions.
Su h on i ts are typi ally resolved using the notion of a namespa e. A namespa e is
like a atalog. When you pla e a name name in a namespa e atalog, the a tual name
you de ne is not name, but atalog::name. Even after a name is pla ed in a namespa e,
it is possible to use just the short version name rather than always needing to use the full
version atalog::name, C++ does provides you me hanisms for that. However, the full
name atalog::name is always available to use if the need arises.
Abhiram Ranade, 2013. Do not distribute 192
It is expe ted that if you reate fun tions for publi use, you will pla e them in a suitably
named namespa e. Thus, if you borrow ode from two programmers, then quite likely they
will use either di erent fun tion names or di erent namespa es. Thus, even if the fun tion
names happen to be the same, by using the full name you an unambiguously refer to ea h
fun tion.
Next we see how to reate and use namespa es. We onsider only the main ideas and
omit many details.
11.3.1 De nition
You an de ne a namespa e named name-of-namespa e and the names inside it by writing:
namespa e name-of-namespa e{
de larations of definitions of names
}
Inside the blo k following the name name-of-namespa e you an de lare or de ne as many
names as you like. For example, you might write:
namespa e mySpa e{
int g d(int,int);
int l m(int m,int n){return m*n/g d(m,n);}
}

After you write this, the namespa e myspa e will ontain the names g d and l m. It is
a eptable to give just a de laration (as we have done for g d) or the omplete de nition (as
we have done for l m). Inside the namespa e blo k, you an refer to the names in it dire tly.
Thus, the de nition of l m refers to g d dire tly. However, outside the namespa e blo k, by
default you must use the full name. For example, after the de nition of mySpa e above, you
may de ne g d by writing the following.
int mySpa e::g d(int m, int n){
if(n == 0) return m;
else return g d(n, m % n);
}
You will note that the last line of the above de nition uses the name g d without pre xing
it with the name of the namespa e. This is ne; the de nition of a fun tion belonging to a
namespa e is onsidered to be an extension of that namespa e, as a result other fun tions
from that namespa e an be referred to dire tly by their short names.
Finally, we an use the fun tions in the namespa e as follows.
int main(){
out << mySpa e::l m(36,24) << endl;
}

This must follow the namespa e de nition and the de nition of mySpa e::g d, and of ourse
in main the full name mySpa e::l m must be used.
Abhiram Ranade, 2013. Do not distribute 193
11.3.2 The using de laration and dire tive
It be omes tedious to keep writing the full name of a fun tion. However, we an use the
shorter form by in luding a so alled using de laration:
using ns::n;

Here ns is the name of a namespa e, and n a name de ned inside it. In the ode following
the using de laration, all referen es to the name n would be onsidered to be referring to
ns::n. Thus we might write

using mySpa e::l m;


If we put this line before the main program, then in the main program we an use l m rather
than having to write mySpa e::l m.
Another variant is to merely state
using namespa e ns;

This is alled a namespa e dire tive. With this, all names in the namespa e ns an be used
using the short form in the ode that follows.
11.3.3 The global namespa e
When you de ne fun tions without putting them in a namespa e, they impli itly enter
an omnipresent, nameless global namespa e. When you use a name without a namespa e
quali er, it is expe ted to be present in either the global namespa e or in a namespa e for
whi h an appropriate using de laration or dire tive has been given.
Suppose we have the namespa e mySpa e as de ned above, and further we have put a
using namespa e mySpa e; dire tive in our main program.
using namespa e mySpa e;

int l m(int m,int n){return m*n;} // not really omputing the l m!

int main(){
out << l m(36,24) << endl;
}

In this ase, the ompiler will ag an error, saying that the referen e l m in the main program
is ambiguous, it ould refer to the l m fun tion in the global namespa e, or the l m fun tion
in mySpa e whi h has been made available through the using dire tive. In su h a ase, you
must give the full name of the fun tion and in doing so pi k one.
To spe i ally refer to a fun tion l m in the global namespa e, you an write ::l m.
Thus in the main program above, you must hange l m to either ::l m or mySpa e::l m.
Note that if the two l m de nitions had a di erent signature, then this problem would not
have arisen.
Abhiram Ranade, 2013. Do not distribute 194
11.3.4 Unnamed namespa es
We dis uss a somewhat te hni al point whi h ould be ignored.
If you de ne a fun tion f in the global namespa e in one le F1. pp, it is potentially
available for use in other les, say F2. pp, provided you ompile the les together, i.e. by
issuing the ommand
s++ F1. pp F2. pp
while ompiling.
Sometimes you might intend the fun tion f to be used only within le F1. pp and not
be exposed outside. For this, you an de ne it inside an unnamed namespa e by writing
namespa e{ // noti e that no name is given
de laration of f
}

With this, you an use f inside the le in whi h the de laration appears, dire lty by its name,
but not outside of the le. You an think of an expli itly reated nameless namespa e as a
global namespa e available only to fun tions in the le in whi h the de laration appears.
11.3.5 Namespa es and header les
Generally, namespa e de nitions are made inside header les, and in su h de nitions only
de larations are put. The fun tion de nitions are put in implementation les, in whi h the
header le ontaining the namespa e de nition must be in luded.
The les that use the fun tions in the namespa e must also in lude the le ontaining
the namespa e de nition, and may use the fun tions in the namespa e either by giving the
full name or by giving a using dire tive and the short name.
Figure 11.3.5 shows an example.

11.4 Global variables


So far in this book we have had variables de ned inside fun tions. However, it is possible,
though not re ommended, to de ne a variable outside all fun tions. In su h ases, the
variable be omes a global variable, i.e. it an be a essed by any fun tion. Note that the
ompiler will typi ally have a separate region of memory where global variables will be
allo ated; global variables are not allo ated in the a tivation frame of any fun tion.
Here is an example.
int i=5; // global variable definition

void f(){ i = i * i; } // refers to global variable

int main(){
out << i << endl; // refers to global variable
f();
Abhiram Ranade, 2013. Do not distribute 195

namespa e mySpa e{
int g d(int,int);
int l m(int,int);
}

(a) The le mySpa e.h


#in lude "mySpa e.h"

int mySpa e::l m(int m,int n){


return m*n/g d(m,n);
}
int mySpa e::g d(int m, int n){
if(n == 0) return m;
else return g d(n, m % n);
}

(b) The le impl. pp


#in lude <simple pp>
#in lude "mySpa e.h"

using namespa e mySpa e;


int main(){
out << l m(36,24) << endl;
}

( ) The le main. pp
Figure 11.2: Program in multiple les using a namespa es
Abhiram Ranade, 2013. Do not distribute 196
out << i << endl; // refers to global variable
}

If you exe ute this ode, the rst statement will print 5, the urrent value of the global
variable i. Then the all f() inside the main program with hange i to 25, whi h will be
printed by the third statement.
Use of global variables is not en ouraged, be ause global variables make ode hard to
understand. Potentially, any fun tion all ould modify the variable, and hen e it is diÆ ult
to make laims about the value taken by the variable at any point of the exe ution. However,
global variables are used in several (espe ially older) programs, and hen e this dis ussion.
We note that a global variable de ned in one le an be used in another le as well.
However, it must be de lared as extern in that le. Thus, to use the global variable i
de ned above in another le, that le would need to have the de laration
extern int i; // de laration, not definition

Note that this does not de ne spa e for i, it merely de lares i to be an int whi h will be
de ned in some other le.
You may also put global variables in namespa es. The simplest way is to pla e the
de laration (whi h is merely the de nition pre xed by extern) inside the namespa e blo k,
whi h an be in a header le. Then one of the implementation les should ontain the
de nition of the variable.
We nally note that individual fun tions may ontain de nitions of a lo al variable having
the same name as a global variable. In su h ases, the lo al variable will shadow the global
variable (Se tion 3.6.3).

11.5 Two important namespa es


The most important namespa e that C++ programmers need to know about is the names-
pa e std.
The namespa e std ontains many names that you might have so far been onsidering
to be reserved words that are a part of the language. Indeed, the words in, out, endl,
as well as the words string and others that you will see soon are in this namespa e. But if
in is in std, you may wonder why you have not been for ed to write std:: in instead of
just in so far. The answer, as you might guess, is that the le simple pp that you in lude
when you write
#in lude <simple pp>
ontains the dire tive using namespa e std;.
Another namespa e important for this book (but not for C++ in general) is the names-
pa e simple pp. All names su h as initCanvas, Cir le, Line, forward, left are in this
namespa e. As you may guess, you an use these names dire tly be ause the le simple pp
ontains the dire tive using namespa e simple pp; also.
Abhiram Ranade, 2013. Do not distribute 197
#in lude <iostream>
#in lude < math>
using namespa e std;

int main(){
out << "Give area of square: ";
double area;
in >> area;
out << "Sidelength is: " << sqrt(area) << endl;
}

Figure 11.3: Contents of the le sidelength. pp


11.6 C++ without simple pp
We now onsider the question of how C++ programs an be written and ompiled without
using simple pp. We show an example le in Figure 11.3.
This le, sidelength. pp an be ompiled using any C++ ompiler, say the GCC
ompiler. Most ommonly the GCC ompiler for C++ is invoked by the ommand g++ as
follows.
g++ sidelength. pp
Everything in the le should look familiar ex ept for the rst two lines. The le iostream
is a header le that ontains de larations of fun tions needed for performing input output.
The le math is a header le that ontains de larations of mathemati al fun tions su h as
sqrt and also other fun tions in luding trigonometri fun tions. You may wonder why did
we not need to in lude these les so far { and the answer of ourse is that we in luded the
le simple pp whi h was in turn in luding these two les.
If you program does not ontain graphi s, then you an dispense with simple pp if you
wish, as seen above for the le sidelength. pp. All you need to do is that instead of
in luding simple pp, you in lude the les iostream and math, and also put in the using
dire tive. Also you also annot use the ommand repeat; but we have already suggested
that you start using the other looping ommands (Chapter 7) instead. Finally, you should
not de ne the main program as main program but de nes it as a fun tion named main.
There are a few other minor features in simple pp that you annot use { and we will dis uss
these as we en ounter them.

11.7 Fun tion Pointers


In Se tion 8.3 we dis ussed the bise tion method for nding the roots of a mathemati al
fun tion f (x). Ideally, we should have written the bise tion method itself as a C++ fun tion,
to whi h you pass the mathemati al fun tion f (x) as an argument. This was not how we
wrote the method then. Instead, we presented ode for the method in whi h the ode for
evaluating f (x) (not a all to it) was inserted as needed. But we an do better now.
Abhiram Ranade, 2013. Do not distribute 198
First, there is the question of how to represent a mathemati al fun tion f (x). The
simplest way is as a C++ fun tion, say f whi h takes a single double argument at returns a
double! But then, we need a way of passing a C++ fun tion (f) as an argument to another
C++ fun tion, whi h we might all, say bise tion.
Figure 11.4 shows how this an be done. This ode ontains C++ equivalents of two
mathemati al fun tions, f (x) = x 2, and g(x) = sin(x) 0:3. The single fun tion
2

bise tion is used to nd the roots of both these fun tions. We will explain how bise tion
works shortly, but rst onsider the main program. As you an see, main alls bise tion for
nding ea h root. Consider the rst all. The rst two arguments to the all are the left and
right endpoints of the interval in whi h we know the fun tion hanges sign. We have used
the same endpoint values as xL,xR of Se tion 8.3, viz. 0,2. The next argument is epsilon,
whi h gives the a eptable error in the fun tion value. For this we have hosen the value
0.0001, instead of reading it from the keyboard. The last argument somehow supplies the
fun tion f whose root is to be omputed. Exa tly why we need to write &f will be ome lear
shortly. The se ond all is similar. We are asking to nd a root in the interval 0 to =2,
where we know that g(0) < 0 while g(1) > 0. Hen e the bise tion method an be applied. So
we all that, spe ifying epsilon as 0.0001. The last two lines merely print out the answers
and he k if the square of the rst answer is lose to 2, and the sine of the se ond answer is
lose to 0.3
First, the key idea. As you know from Se tion 2.8, ode and data are both pla ed
in memory. Just as we an identify a variable by its starting address, we an identify a
fun tion also by the address from where its ode starts. Thus C++ has the notion of a
fun tion pointer, whi h you ould think of as the starting address of the ode orresponding
to the fun tion. On e we have a pointer to a fun tion, we simply dereferen e it and use
it! Thus, the expressions &f and &g are merely pointers to our fun tions f,g. So all that
remains to explain is how the fun tion bise tion will dereferen e and use them.
The name of the last parameter of bise tion is pf. We explain its ompli ated looking
de laration soon. In the body, this parameter pf indeed appears dereferen ed. In the rst line
it appears as (*pf)(xL), where the parentheses are ne essary be ause just writing *pf(xL)
will be interpreted as *(pf(xL)) whi h is not what we want. Noting that dereferen ing
works exa tly as we expe t, the expression (*pf)(xL) will indeed evaluate to f(xL) when
pf has value &f. Similarly the expression (*pf)(xM) will evaluat f(xM). Thus this ode will
work exa tly like the ode in Se tion 8.3 for the rst all.
So the only thing that remains to be explained now is the rypti de laration of the
last parameter of bise tion. Basi ally we need a way to say that something is a fun tion
pointer. Note that bise tion an only be used to nd roots of fun tions of one real variable,
i.e. it does not make sense to pass a fun tion su h as g d (whi h takes 2 int arguments and
returns an int). Pointers to only ertain types of fun tions are a eptable as arguments to
bise tion: spe i ally pointers to fun tions that take a single double argument and return
a double as result.
First, let us onsider how to de lare a fun tion that takes a double as argument and
returns a double result. If the name of the fun tion is pf, then we know from Se tion 11.2.1
that it an be de lared as:
double pf(double); // pf is a fun tion taking double and returning double
Abhiram Ranade, 2013. Do not distribute 199

double f(double x){


return x*x -2;
}

double g(double x){


return sin(x) - 0.3;
}

double bise tion(double xL, double xR, double epsilon, double (*pf)(double x))
// pre ondition: f(xL),f(xR) have different signs. ( >0 and <=0).
{
bool xL_is_positive = (*pf)(xL) > 0;
// Invariant: x_L_is_positive gives the sign of f(x_L).
// Invariant: f(xL),f(xR) have different signs.

while(xR-xL >= epsilon){


double xM = (xL+xR)/2;
bool xM_is_positive = (*pf)(xM) > 0;
if(xL_is_positive == xM_is_positive)
xL = xM; // maintains both invariants
else
xR = xM; // maintains both invariants
}
return xL;
}

int main(){
double y = bise tion(1,2,0.0001,&f);
out << "Sqrt(2): " << y << " he k square: " << y*y << endl;

double z = bise tion(0,PI/2,0.0001,&g);


out << "Sin inverse of 0.3: " << z << " he k sin: " << sin(z) << endl;
}

Figure 11.4: Bise tion method as a fun tion


Abhiram Ranade, 2013. Do not distribute 200
But now we simply note the general strategy for de laring pointers: if a de laration de lares
name v to be of type T, then repla e v by *v and the new de laration will de lare v to be
pointer to T . Doing this we get what we wanted.
double (*pf)(double); // *pf is fun tion taking double and returning double
// pf is pointer to fun tion taking double and returning double
where the parentheses have been put to avoid asso iating * with double.
De laring pointers is somewhat tri ky and rypti . It takes a bit of pra ti e to write su h
de larations and even read them. To take another example, this is how you would de lare
ph to be a pointer to a fun tion whi h takes a double and int as argument and returns a
double.
double (*ph)(double,int);
Perhaps the best way to read it is the reverse of what we did above. Repla e *ph by h
and observe that h must be a fun tion taking double,int arguments and returning double.
Hen e *ph must be a pointer to su h a fun tion.
11.7.1 Some simpli ations
The C++ standard allows you to drop the operator & while passing the fun tion, and also
the dereferen ing operator * while alling the fun tion. Unfortunately, this does not help in
the tri kiest part, the de laration of a fun tion pointer parameter.

11.8 Con luding remarks


This hapter dwelled on many te hni al aspe ts of using fun tions. However, there is an
important philosophi al aspe t whi h we onsider below.
We also dis ussed the notion of fun tion pointers. However, in C++ some additional
me hanisms have been introdu ed for similar fun tionality. These will be dis ussed in Se -
tion 16.4 and Appendix H.
11.8.1 Fun tion size and readability
We began this hapter by proposing fun tions as a me hanism for avoiding ode dupli ation.
This is indeed a very important use of fun tions. However, fun tions an also be used to
make your ode easier to understand to other programmers. Ease of understanding is very
important espe ially when programmers work in teams.
One way to improve understandability of anything is to present it in small hunks. When
you write a book it is useful to break it up into hapters. A hapter forms an organizational
unit of a book. In a similar manner, a fun tion forms an organizational unit of a program.
There are a few thumb rules for breaking long text into hapters or se tions. An example of
a thumb rule: every idea that is important should have its own hapter, or its own se tion.
There are similar thumbrules for splitting large programs into fun tions.
When it omes to programming, it is often believed that no fun tion, in luding main
should be longer than one s reenful. Even with large displays, this gives us a limit of perhaps
Abhiram Ranade, 2013. Do not distribute 201
40-50 lines on the length of a fun tion. Basi ally, you should be able to see the entire logi
of the fun tion at a glan e: that way it is easier to understand what depends upon what, or
spot mistakes. How do we break a program into smaller pie es? So far you have not had the
o asion to write programs longer than 40 lines, so this dis ussion is perhaps a bit diÆ ult
to appre iate. You will see later, however, that most programs an be thought of as working
in phases. Then you should onsider writing ea h phase as a separate fun tion, and give
it a name that des ribes what it does. These fun tions ould be pla ed in the same le as
the main program, but you will nd that this will make the program easier to understand.
Another idea is to make a fun tion out any modestly ompli ated operation you may need
to perform. As an example of this, onsider the apparently simple a tion of reading in a
value from the keyboard. As noted in Se tion 7.3, a user might type in an invalid value,
or the value may not stand for itself but in fa t might indi ate that the stream of values
has nished. One way is to pla e the logi for dealing with all this in a fun tion that is
alled by the main program. This idea is partly explored in the read marks into fun tion
of Se tion 9.7.

11.9 Exer ises


1. Suppose the LCM omputation program of Figure 11.1 has been written using a single
le, and it is noti ed that only the fun tion l m has been de lared and also de ned,
all other fun tions are de ned but not de lared. Show how the program ould appear
in the le.
2. The fun tion passed to the bise tion fun tion took a float and returned a float.
However, we might well need to nd the root of a fun tion whi h takes a double and
returns a double. Also, it would be ni e if the types of the other arguments were
likewise made double. Turn bise tion into a template fun tion so that it works for
both double and float types. You an of ourse also do this by overloading the name
bise tion.
Chapter 12

Pra ti e of programming: some tips


and tools

In theory, theory and pra ti e are the same. In pra ti e, they are not.
Albert Einstein

If you have been reading this book without solving any of the exer ises, you may perhaps
ome to believe that the pro ess of developing a program is neat and tidy, and generally
smooth sailing. If on the other hand, you have also been solving the exer ises, your experien e
might be di erent. After you write a program, you ompile and run the program and you
test it by providing di erent inputs. You possibly dis over that for some input, let us all it
x, the program does not produ e the orre t output. After some amount of dete tive work
you gure out why the program is not produ ing the orre t answer for x; so you modify
your program (often alled \debugging") and rerun. You then dis over that now the program
works orre tly for x, but it does not run orre tly for an input y, for whi h the old program
was orre t! So you have to do more dete tive work. And this y le an go on for some time.
If you are writing large programs, this y le an be extremely frustrating.
In this hapter, we will dis uss the entire programming pro ess and o er suggestions with
a view to (a) in rease the on den e that the program is doing what it is supposed to do,
and (b) make the pro ess less tiresome.
The program development pro ess starts with learly understanding what is to be done,
i.e. the spe i ation for the program. Along with understanding the spe i ation abstra tly,
it is useful to onstru t examples of inputs and required outputs. These help in ensuring
that the spe i ation is orre t, and an also be used to test the program when it is written.
After dis ussing spe i ation we will omment brie y on program design. Finally we will
also make some remarks on the debugging pro ess. Along the way, we will also remark
on some general fa ilities like input-output redire tion and assertions that are available to
simplify the above steps. In some ways, this hapter is an extended version of Chapter 4.
Some of the suggestions made in this hapter may strike you as being too autious, you
may think, \I an go mu h faster than this". In ase you are one of the lu ky few who an
write large programs orre tly, in an intuitive manner, without apparent areful planning,
more power to you! But if you nd you are spending more time debugging the program than
designing it in the rst pla e, you are en ouraged to try out the suggestions given in this
hapter.

202
Abhiram Ranade, 2013. Do not distribute 203
12.1 Clarity of spe i ation
The rst step in writing a orre t program is to learly know what you want the program to
do. This might sound obvious, but often, programs dont work be ause the programmer did
not learly onsider what needs to happen for some tri ky input instan e. How an you be
sure that you ompletely know what the program is expe ted to do, that you have onsidered
all the possibilities? The best way for doing this is to write down the spe i ations very
learly, in pre ise mathemati al terms if possible.
Typi ally, in a spe i ation you will state that the inputs onsist of numbers x; y; z; : : :,
and the output onsist of the numbers p; q; r; : : :. Then you will give onditions that these
numbers must satisfy. The spe i ation is not expe ted to indi ate how the output is to
be a tually generated, that is to be de ided by your program, sometimes referred to as
the implementation. If the output produ ed by your implementation happens to satisfy
the onditions des ribed in the spe i ation for every input, then and only then an your
implementation be erti ed as orre t. It is a good idea to write the spe i ation as a
omment in your program, and also to use the same variable names in the spe i ation as
in your program.
Let us take an example. What are the spe i ations for the program to ount digits of
a number? We think that we understand de imal numbers, whi h we indeed do. But su h
intuitive understanding does not onstitute a spe i ation. The intuitive understanding
must be explained in more pre ise terms. Here is the spe i ation we used earlier.
Input: A non negative integer n.
Output: Smallest positive integer d su h that 10d > n.
This is a good spe i ation be ause it gives the pre ise onditions that we want the
output to satisfy, nothing more, nothing less.
It is ustomary in writing spe i ations to state onditions in the form \smallest/largest...
satisfying... ". Formulating spe i ations in this manner requires some pra ti e. Also a
lot of are is needed. Should the ondition be 10d > n or 10d  n? You may onsider
these questions to be tedious, but if you annot answer them orre tly while writing the
spe i ation, you are unlikely to write the program orre tly. You may be making the same
mistake in your program!
Let us onsider another problem. Suppose you are given n points in the plane, p ; : : : ; pn.
1
Find the smallest ir le that ontains all the points. It might be tempting to rewrite just
what is stated in the problem statement:
Input: n points p ; : : : ; pn in the plane.
1

Output: Smallest ir le that ontains all points.


In this we have not spe i ed how a ir le is to be represented using numbers. That is
a eptable, if our audien e knows how to represent ir les using numbers and translate the
phrases su h as \smallest ir le", and \ ontains all points", into onditions on numbers. For
the present, however, we will prefer the following des ription of the output.
Abhiram Ranade, 2013. Do not distribute 204
Output: Real numbers x; y; R su h that the distan e between ea h point pi and the point
(x; y) is at most R, and R is smallest possible.
In this, we have not de ned what \distan e" means. If that is not expe ted to be ommonly
understood, then we should spell it out too.
Consider another example.
Input: n points p ; : : : ; pn in the plane spe ifying the verti es of a polygon in lo kwise or
1
ounter lo kwise order.
Output: Area of the polygon.
This seems like a good spe i ation. Although we have not given a formula to ompute
the area, the notion of area is ommon knowledge. Or is it? As you think more about
the problem, you will realize that there is no standard notion of area, if the line segments
interse t, i.e. if the polygon is not simple. If we allow non-simple polygons as input, the
problem statement needs to de ne what area means for non-simple polygons. Suppose the
user expe ts to supply only simple polygons as input. In that ase, the input must be
des ribed as su h.
Input: n points p ; : : : ; pn in the plane spe ifying the verti es of a simple polygon in lo k-
1
wise or ounter lo kwise order.
This spe i ation doesnt state what is expe ted to happen if the input spe i ed during
exe ution is invalid, say the polygon a tually given as input is not simple. Indeed, that is
not a part of the ontra t between the implementer and the user of the program. If the
input polygon is non-simple, the program may give junk values, or may not even terminate.
If any other behaviour is expe ted, then it should be made a part of the spe i ation. 1

The points to note are as follows. First, write down spe i ations as pre isely as possible,
using mathemati al notation if it is reasonably obvious. Se ond, you may re eive a spe i -
ation that looks ne, but really is not properly de ned. In this ase, you should modify it.
Finally, it might be possible to supply input whi h does not adhere to the spe i ation, e.g.
the user an supply a non-simple program as input. If this happens, the implementer need
not guarantee any spe i output.

12.2 Input-output examples and testing


Along with writing the spe i ations, you should onstru t sample input instan es, and
work out what output you want for those. As dis ussed in Se tion 4.1.1, it is good to have
examples in your mind for any abstra t statements you make. Another reason is that the
input-output examples you work out will serve later as test ases for your program.
For the digit ounting program, it is easy to work out examples. For example you might
de ide to have your rst input instan e be the number 34, for whi h the output must be 2
sin e that is the number of digits in 34. This might appear too easy, but even so it should be
Note that a more omplex spe i ation will typi ally lead to a slower program. Hen e in this ase it
1
might be better to have two programs: one for simple polygons and another for possibly non-simple polygons.
Abhiram Ranade, 2013. Do not distribute 205
written down. You should also he k whether the input (34) and the output (2) agree with
the what you have written down in the spe i ation: Is 2 indeed the smallest number su h
that 10 > 34? These may sound like trivial he ks, but your program an go wrong be ause
2

of trivial mistakes, and so su h he ks are useful. For the ir le overing problem, working
out examples is harder, sin e it might take onsiderable al ulation to nd the smallest
overing ir le by hand. In su h ases, the least you an do is to onstru t a few simple
ases, e.g. just two points, say (0,0) and (1,0), for whi h the best overing ir le must have
radius 0.5 and must be entered at (0.5,1).
If you want to design examples that will serve as test ases later, you should think about
what examples are \good". For this there are a few strategies. One idea is to generate
what you think might be \usual" instan es whi h somehow you think might be \ ommon
in pra ti e". For example, for the overing ir le problem, the instan e in whi h all points
are randomly pla ed in the plane is perhaps more ommon than the instan e in whi h they
are all ollinear. It is possible that for some other problem (say ounting digits) there is
no notion of \ ommon in pra ti e". Even in this ase you an think of using random input
values. You may wonder how you an feed random numbers to a omputer. We will dis uss
this in Se tion 12.7.
Another possiblity is to onsider if some input instan es are \harder" than others, and
hen e might test the program better? The notion of hard is of ourse informal. But here is
how you might onsider ertain inputs more interesting, say for the digit ounting problem.
If you look at the number of digits d as a fun tion of the input n, you will see that d
hanges at powers of 10. At 9 the output value is 1, but it goes up to 2 at 10. The value
is 3 at 999 but goes up to 4 at 1000. So you might want to pay more attention to these
input values: perhaps the program has to be \keenly attentive" and distinguish between 999
and 1000 (even though they are onse utive), but not between 578 and 579 (whi h are also
onse utive). So he king the inputs 999, 1000 and so on might be more likely to show up
the errors, than say he king 578 or 579. Another ase of ourse is to he k for the smallest
and largest input values allowed. In ase of digit ounting 0 is the smallest value allowed,
and whatever the largest value allowed is for representing n on your omputer. The smallest,
largest, and the values at whi h the output hanges are informally alled \ orner ases", and
you should ertainly test around these values.
For the polygon area problem, the simplest input instan es ould be re tangles, for whi h
it should be easy to al ulate the area by hand. You ould again ask, what input instan es
are easy and whi h are hard? The polygons need to be simple, but of ourse they need
not be onvex. So if you plan to allow non- onvex polygons as input, then ertainly they
should be a part of your test instan es. If you de ide that you dont want to allow non- onvex
instan es, then you should amend the spe i ation to de lare this. Note that it is better
that your program orre tly implements a weaker spe i ation than wrongly implementing
a stronger one.
The length of the input is not xed for the polygon area problem. Very likely the
program will rst read in n the number of verti es, and then the oordinates of the points.
An important question to answer is how your program will handle orner ases, e.g. n = 2
or n = 1 or even n = 0. Either you should return 0, or you state learly in the spe i ation
that these ases will not be handled by your program.
Abhiram Ranade, 2013. Do not distribute 206
12.3 Input/output redire tion
When you write programs professionally, you are required to keep a re ord of the testing
you have done. This an be done ni ely by using a feature alled input redire tion. Most
operating systems support input redire tion.
In Chapter 1 we told you that in represents the keyboard and whenever your program
exe utes a statement of the form in >> ... you are expe ted to type in an appropriate
value. This is an oversimpli ation. If fa t, in represents an abstra t, standard input
devi e, whi h is the keyboard by default, but this default an be hanged. If you wish, you
an make the standard input devi e be a le, say named file1. Thus, instead of waiting for
you to type in input, the program would take input from le file1 whenever it exe utes a
in >> ... statement. This is alled input redire tion. To redire t input, you spe ify the
name of the le on the ommand line, pre eded by the hara ter <, after the name of the
exe utable. Thus to redire t input to ome from file1, you will type the following on the
ommand line.
% a.out <file1
As you an see, input redire tion is very onvenient. Even before you write the program,
ea h test instan es you reate as dis ussed above an be pla ed in a le. When the program
is ready, you run it, merely redire ting input so that the data omes from the le of your
hoosing.
Thus we an suggest the following pro ess for reating and using test ases. Even before
you write the program reate test ases, pla ing the input in les, one le per instan e.
Thus you will reate several les, say input1.txt, input2.txt, ... . Also reate les
output1.txt, output2.txt, ... whi h ontain the outputs as you expe t for the or-
responding input instan es. After the program is ready, simply redire t input, say from
input3.txt in order to test it on the third instan e you reated. Che k that the output you
get is indeed what you had written down in output3.txt.
Note by the way that input redire tion is also useful if your program does not run orre tly
on the very rst run. If you have pla ed the data in a le then you an redire t input from
it, and thus do not have to type the data again and again. This saves typing e ort, and is
espe ially useful for programs for whi h the input is large.
Note nally that the standard output stream, out an also be redire ted. For this you
an exe ute your program by typing
% a.out >file2
If you do this, whatever you print by exe uting out << ... in your program will be pla ed
in the le file2, rather than being shown on the s reen.
This is useful for programs whi h the output is large. If the output is put into a le, you
an examine it at leisure. Also, the le thus reated an serve as a re ord of your testing
a tivities.

12.4 Algorithm design


The next step after the development of the spe i ations and test ases is algorithm design.
By algorithm we mean the abstra t ideas we need to solve a problem. For example, how do
Abhiram Ranade, 2013. Do not distribute 207
we nd the smallest ir le overing a set of points? This problem has a puzzle like avour,
and seems to require some reative thinking. You might even wonder whether reativity
an be taught. But there do exist strategies for designing algorithms. As we have been
mentioning frequently, re ursion is one strategy. However, algorithm design is really outside
the s ope of this book.
For the most part, whatever algorithms you need to know in order to write programs
des ribed in the text and the exer ises, we will either tell you dire tly, or they will be minor
modi ations of algorithms you somehow know already. And do realize that you know a lot
of algorithms already. Indeed from hildhood you have been learning a lot of algorithms,
how to multiply two numbers, how to ook, how to ride a bi y le, and so on. You will need
to express some of these algorithms using C++. This will not ne essarily easy, you may be
exe uting the algorithms sub ons iously, out of habit, but you will have to introspe t on your
a tions and identify the patterns in them and express them in C++. This may be possible
for some problems, e.g. multiplying one number with many digits by another number, but
very diÆ ult for others, e.g. riding a bi y le. In any ase, for the most part you should not
need serious algorithm design, but you should ertainly be able to introspe t over skills you
have learnt sin e hildhood, verbalize them and express them in C++. In addition to that,
some amount
How to generate su h ideas is dis ussed elsewhere in the book. Our on ern for now is
2

how to organize your program assuming you understand the spe i ations, have reated the
test ases, and know all the relevant mathemati al/algorithmi ideas. That is what we mean
by program design.
We remarked in Se tion 11.8.1 that any large program is best written by dividing it into
small fun tions. Later we will see other ways of dividing programs into pie es, but the key
point is that some su h division will need to be there. On e you de ide to divide a large
program into pie es, we really need to apply the program design pro ess (re ursively!!) to
ea h pie e. We must write out the spe i ation for ea h pie e (fun tion), and design test
ases for ea h fun tion too. It is tempting to not test the individual fun tions, but to put
together the entire program, and see if the whole thing behaves orre tly. But if the whole
thing does not behave orre tly, it is tri ky to gure out whi h fun tion is not working right.
So it is useful to rst test ea h fun tion separately. This means simply that if your program
needs to al ulate GCD very often, do write a GCD fun tion, and then test it before you put
it together with the rest of the program. Quite likely this will save you time in debugging
later.
The idea of writing spe i ations applies even in implementing a fun tion itself. Say
when you design a loop, you should be lear in your mind as to what the loop is intended
to a omplish (spe i ation), and be able to reason about it by writing invariants and a
potential fun tion. It is also a good idea to put these down as omments. Basi ally these are
all \defensive programming strategies" intended to minimize the han e of making mistakes.
Another important program strategy is as follows. Suppose you are writing a program
whi h solves a somewhat omplex problem. The natural plan might be to write a program
to solve the entire problem in the very rst attempt. Another idea is: onsider a weaker
spe i ation rst. Write the program to solve the weaker spe i ation, testing it ompletely.
Then try your hand at the original spe i ation. The idea behind this weaker spe i ation
2 The exer ises give you some hints about the overing ir le problem.
Abhiram Ranade, 2013. Do not distribute 208
rst strategy is as follows. You may think that you understand the grand spe i ation.
But often you may not, espe ially if you are inexperien ed. As you try to implement the
simpler spe i ation you may realize the problem needs more thought. Thus it is best to
get on with writing ode reasonably qui kly { that experien e will help you understand the
diÆ ulties. The other alternative is to develop the full spe i ation rst and only then start
writing the program, and start testing only after the entire program is ready. In this you
deny yourself the feedba k (not to mention the satisfa tion!) that you get from doing some
testing. Be ause of the early feedba k, the weak spe i ation rst approa h might end up
saving time and e ort.
As an example onsider the polygon area problem. You may know Heron's formula for
the area of a triangle given the lengths of the sides:
p
Area = s(s a)(s b)(s )
where a; b; are the lengths of the sides of the triangle, and s = a b . Using this you may
+ +

onsider it easier to al ulate the area of a onvex polygon, than that of non- onvex one.
2

So in this ase, the weak spe i ation rst strategy would en ourage you to rst write the
program for the onvex ase. However the key point is that whatever you do, you should
work to a spe i ation, weak or strong. In other words, there must be truth in advertising!
12.4.1 Mentally exe ute the program
Mu h of the advi e being doled out in this hapter may be onsidered \obvious", and indeed
it is. However, experien e shows that human beings do not always take obvious pre autions
(e.g. wearing seatbelts in ars). So it is worth reiterating even obvious pre autions and
putting up a he klist.
Here is one su h simple habit worth developing. After you nish writing a program
and before you a tually exe ute it, take a simple input instan e and mentally exe ute your
program if possible. This may be diÆ ult for large programs, but it will help a lot while
you are learning. For example, onsidering the digit ounting program, you should mentally
exe ute your program on some small input and satisfy yourself that it is orre t. The mental
exe ution will often alert you to some errors.
12.4.2 Test ases for ode overage
We have already talked about designing test ases before the program is written. However,
some additional test ases may be usefully designed after after the program development
nishes. The basi idea is: the test ases on whi h you run your ode must exer ise every
pie e of ode that you wrote. This is important if your ode has many if statements, say
nested inside one another.
We will onsider this issue in some exer ises later, e.g. Exer ise 9 of Se tion ??.

12.5 Assertions
The import of the previous dis ussion is: you should know your program well.
Abhiram Ranade, 2013. Do not distribute 209
Your knowledge of the program is often of the form: \at this point in the program, I expe t
the value of this variable to be at least 0". Why not a tually he k su h expe tations during
exe ution? If your program is not running orre tly, it might well be be ause something that
you on dently expe t is not a tually happening.
C++ ontains a fa ility whi h makes it easy to he k your expe tations and produ e
error messages if the expe tations are in orre t. Suppose you express a ertain ondition
ondition to hold at a ertain point in your program, you simply pla e the statement
assert( ondition);
Here ondition must be a boolean expression. When ontrol rea hes this statement,
ondition is evaluated, and if it is false, the program halts with a message, typi ally stating
\Assertion failed", and the line number and the name of the program le ontaining the
assertion is also given. If the expression ondition is true (as you expe ted it to), then
nothing happens and the ontrol just moves to the next statement.
To use assert you must in lude the line
#in lude < assert>
at the top of your le.
For example, in the g d fun tion of Figure 9.1, you expe t the parameter n to be positive.
Thus you ould pla e the line
assert(n>0);
as the rst line of the fun tion body. If during exe ution g d is alled with the se ond
argument 0, you would get an error message saying that this assertion failed.
Here is another example. Suppose you know that a ertain variable v will only take values
1 or 2. The you might originally have written:
...
if(v == 1) ...
else if(v == 2) ...
...
You might not write the else statement following the if else thinking that it is not ne -
essary. But \the statement is not ne essary" is only your expe tation. If the value of the
variable v has arisen after a ompli ated al ulation, it is on eivable that something might
have gone wrong in your dedu tion. If you are debugging your program, then you want to
be sure that your \ on dent dedu tion" is a tually orre t, before you start suspe ting the
rest of the program. So you ould a tually make a he k by writing an assertion.
...
if(v == 1) ...
else if(v == 2) ...
else assert(false); // exe uted only if v is not 1 or 2.
...
If this assertion did not fail during exe ution, you know that the problem must be elsewhere.
We will see more examples of assertions later, e.g. for array bounds he king (Se -
tion 13.8).
Abhiram Ranade, 2013. Do not distribute 210
12.5.1 Disabling assertions
Assertions are meant to be used in the debugging phase, when you are not ompletely sure
about the orre tness of your program. On e you be ome sure of the orre tness of your,
you may want to remove the assertions. This is be ause he king the assertions will take
some time and will slow down the program. But it might be umbersome to go through all
the ode and physi ally remove the assertions.
It turns out that is possible to disable assertions pla ed in your program without physi-
ally removing them. For this you put in the line
#define NDEBUG

at the top of ea h le ontaining assertions you want to disable. The above line is to be pla ed
before the in lusion of < assert>. The above line will de ne the prepro essor (Appendix G)
variable NDEBUG. This will have the e e t of turning the assert statement into a omment.

12.6 Debugging
Suppose you follow the above dire tions and are generally very areful, and yet things go
wrong: your program produ es an answer di erent from what you expe t. What do you do?
The most natural response is to try and nd out when the program starts behaving
di erently from what you expe t. For this, you an print out the values of the important
variables at some onvenient halfway point, and he k if the values are as you might expe t.
If the values printed by these statements are as you expe t (or not), then the error must
be happening later (earlier), so you put print statements at later (earlier) points in your
program. By examining the values in this manner, you try to get to a single statement until
whi h the values are as you expe t, but after whi h the values are di erent. At this point,
you are usually in a position to determine what is going wrong. The pro ess of examining
the values taken by variables during exe ution an be made mu h easier if you use programs
alled debuggers or IDEs. We dis uss them below.
We do note one important sour e of errors: it might be the ase that your program is
not working orre tly not be ause it has a logi al aw, but be ause it is not being fed the
orre t data. This an happen espe ially if the input is oming from a badly designed input
le whi h you have redire ted. We dis uss how to deal with this.
12.6.1 Debuggers and IDEs
There exist spe ialized programs, alled debuggers or IDEs, Intera tive Development En-
vironments, whi h are modern versions of debuggers, whi h an substantially help in the
pro ess of debugging.
Debuggers or IDEs o er many ways of exe uting your program. For example, you an
ask that the program be stepped, i.e. run one statement at a time. You an see where the
ontrol is after the exe ution of the statement in question ends, and you an also examine
the values of the di erent variables. You an also ask that the program exe ute until a
ertain statement is rea hed, exe uting freely till that statement. On e that statement is
Abhiram Ranade, 2013. Do not distribute 211
rea hed, you an again examine variable values if you wish. Essentially, this enables you to
investigate how your program exe utes without having to put in print statements in it.
Unfortunately, most IDEs are fairly omplex, and it is signi ant work to just understand
how to use them. That is the reason we have not dis ussed IDEs in this book. But if you
plan to write programs with thousands of lines of ode, you should learn to use IDEs.
12.6.2 End of le and data input errors
C++ behaves in a somewhat unintuitive manner in data input. Suppose you exe ute in
>> x; where x is of type int. Suppose the value typed in response to this (or read from
the le from whi h in is redire ted) happens to be the hara ter 'a'. If this happens you
might expe t that the program will halt with an error message. However the program does
not halt! Instead, some junk value is supplied to you and the program ontinues merrily.
The only indi ation that an error has happened is that the value of in be omes 0, or
NULL. So ideally, after reading every value you should he k if in is not NULL. For this you
an write an assertion:
assert( in != NULL);
or you an even shorten it to:
assert( in);
This is be ause NULL or 0 also stands for the logi al value false.
The main point to note is as follows. Suppose your program is not working orre tly.
It ould be be ause of a data input error. You may be feeding it an illegal value. This is
not likely to happen if you are a tually typing in values from the keyboard in response to
messages from the program. However, if the program is reading data from a le (be ause
of redire tion or otherwise) it may well happen. So it is best to he k for input errors by
asserting in.
12.6.3 Aside: Input-Output expressions
Finally, we note that in C++ the phrase in >> value auses a value to be read into the
variable value, and in addition itself is an expression that has a value: the value of the
expression is the value of the variable in. This should not ome as a surprise to you, this
is in fa t the reason you an write statements su h as in >> a >> b; whi h you should
really read as ( in >> a) >> b; where the rst expression auses a value to be read into
a, and then the expression evaluates to in, from whi h another value is read into b.
This fa t allows us to write some rather ompa t loops. Suppose you want to nd the
sum of a sequen e of numbers stored in a le. You an do this by exe uting the following
program with in redire ted from that le.
int main(){
int val, sum=0
while( in >> val){ // file read in the loop test
sum += val;
Abhiram Ranade, 2013. Do not distribute 212
}
out << sum << endl;
}
The reading happens in the loop test, and if there is an error or end of le, the reading
expression returns false, and the loop ends. Thus the above loop will end when the le ends,
and after that the sum will be printed.
Note that you an also use the above program to sum values that you type in from the
keyboard. Just type in the values, and follow them with a trl-d (type 'd' while the ontrol
key is pressed), whi h signals an end of le.

12.7 Random numbers


C++ provides you with the fun tion rand whi h takes no arguments whi h returns a random
number. This statement should puzzle you { a omputer is an orderly deterministi ma hine,
indeed we did not say anything about randomness in our dis ussion of omputer hardware
(Chapter 2). How an then a omputer generate random numbers?
Indeed, a omputer does not generate truly random numbers. Instead, a omputer merely
generates su essive numbers of a perfe tly deterministi omputable sequen e whose ele-
ments seem to be resemble a sequen e whi h ould have been generated randomly. Su h
sequen es and their elements are said to be pseudo-random. Indeed a simple example is the
so alled linear ongruential sequen e, given by say, xi = a  xi + b mod M , where a; b; M
1
are suitably hosen integers. Say we hoose, just for the purpose of dis ussion, a = 37,
b = 43, M = 101. Then starting with x = 10, the next few terms are: 9, 73, 17, 66, 61, 78,
0
0, 43, 18, 2, 16. Perhaps you will agree informally that this sequen e looks random, or at
least more random than the sequen e 0, 1, 2, 3, 4 and so on. It is possible to formalize what
pseudo-random means, but that is outside the s ope of this book. So we will just assume that
pseudo-random merely gets the best of both worlds: it is a sequen e that an be generated
by a omputer, but an be onsidered to be random for pra ti al purposes.
Fun tions su h as rand whi h return (pseudo) random numbers do use the general idea
des ribed above: the next number to be returned is omputed as a arefully hosen fun tion
of the previous. So the exa t sequen e of numbers that we get on su essive alls to rand
depends upon how we started o the sequen e, what x we hose in the example above. This
0
rst number of the sequen e is often alled the seed. C++ allows you to set x to any value
0
v you wish by alling another fun tion srand whi h takes a single integer argument whi h
you must spe ify as v. To use rand and srand, you would normally need to in lude the line
#in lude <stdlib.h>
But this is not needed if you are in luding <simple pp>.
A all rand() returns an int in the range 0 to RAND MAX. This name is de ned for
you when <stdlib.h> is in luded. You an onsider the returned value to be uniformly
distributed, i.e. the value is equally likely to be any integer between the spe i ed limits.
Finally, an important point about pseudorandom sequen es. The sequen e you get when
you x the seed is always the same. This is a desirable property if you will use it to generate
input data. This is for the following reason. Suppose your program is not working orre tly
Abhiram Ranade, 2013. Do not distribute 213
for ertain (randomly generated) data. Say you modify the program and you wish to he k
if it is now orre t. Had the data been truly random, it would be unlikely that the same
sequen e would get generated during the exe ution. However, sin e you use a pseudo random
sequen e, you are guaranteed to get the same sequen e if you set the same seed!
Of ourse, you might also want to the program to run di erently on ea h o asion. In
su h ases, you an use the ommand time to set the seed, i.e. write
srand(time());

The time ommand returns the urrent time in se onds sin e some midnight of January 1,
1970, or some su h moment. Clearly, you an expe t it to be di erent on ea h run.
12.7.1 The randuv fun tion in simple pp
In simple pp we have provided the fun tion randuv whi h takes two double arguments
u,v and returns a random double in the range u through v. Our ommand alls the C++
supplied fun tion rand, and returns the following value:
u + (v-u)*rand()/(1.0 + RAND_MAX)
As you an see this value will be between u and v and uniformly distributed to the extent
rand is uniformly distributed.
If you want random numbers between integers i,j, you must all randuv(i,j+1) and
onvert it to an integer. This will give you uniformly distributed integers between i and j.
You an use srand to set the seed as before.

12.8 Con luding remarks


We began the hapter by stressing the need to learly understand the spe i ation; indeed
many errors happen be ause the spe i ations are not properly understood by the program-
mer. We also dis ussed some strategies for developing test ases.
We dis ussed a few tools for helping the pro ess of program development: input/output
redire tion, and assertions.
As to debugging, the main idea suggested was to put in print statements to see whether
the program was exe uting as per your expe tation. We also pointed out the possibility of
errors in data input, and how to deal with them. As an aside we dis ussed the notion of
input expressions, using whi h you an read till the end of the le, without knowing how
many values are present in the le.
We also dis ussed (pseudo) random number generation, whi h will be useful for generating
random input instan es. But (pseudo) random numbers are also useful used in general, e.g.
Chapter 25.
You may nd many suggestions in this hapter to be very autious, if not paranoid.
But when it omes to serious programming, it is better in the long run to be humble and
paranoid.
Abhiram Ranade, 2013. Do not distribute 214
12.9 Exer ises
1. For the digit ounting problem ould the ondition 10d > n be 10d  n instead? What
if we did not require d to be a positive integer? Give a risp answer, i.e. give inputs
for whi h the new spe i ations would require an answer di erent (wrong!) from that
required by the old one.
2. Here is a \ lever" observation about the digit ounting problem. Suppose a number
n has d digits. Then bn=10 has d 1 digits. Thus we simply ount the number of
times we an divide by 10 till we get zero and that will be the number of digits of the
number. So the program is:
main_program{
int n, d=0;
in >> n;

while(n>0){
n = n/10;
++d;
}

out << "There are "<<d<<" digits.\n";


}

Is this program orre t? Would you have written this program if you had followed the
pro ess suggested in this hapter? For what values of the input would you test the
program?
3. Write the program that nds the smallest ir le overing a given set of points. Allow
the user to supply the points by li king on the s reen, and show the smallest ir le
also on the s reen. Hint: Argue that the smallest overing ir le must either have as
diameter some two input points, or must be a ir um ir le of some three input points.
Now just onsider all possible andidate ir les, and pi k the one that a tually overs
all points.
4. What are good test ases for the smallest overing ir le problem?
5. Design input instan es to test the in ome tax al ulation problem of Chapter 6.
Chapter 13

Arrays

Here are some real life problems that we may want to solve using omputers.
 Given the marks obtained by students in a lass, print out the marks in non-de reasing
order, i.e. the smallest marks rst.
 Given a road map of India nd the shortest path from Buldhana to Jhumri Talaiya.
 Given the positions, velo ities and masses of stars, determine their state 1 million years
from today.
In prin iple, we ould write programs to solve these problems using what we have learned so
far; however there will be some diÆ ulties be ause of sheer size: our programs might have
to deal with thousands of stars or hundreds of students or roads. Even writing out distin t
names for variables to store data for ea h of these entities will be tiring.
Most programming languages provide onvenient me hanisms using whi h we an tersely
deal with large olle tions of obje ts. In C++ there are two su h me hanisms.
1. Arrays: This is an older me hanism whi h was also present in the C language, and as
a result an also be used in C++. In this hapter we will onsider arrays at length.
2. Ve tors: This is a newer me hanism, whi h is only present in C++. In C++ programs,
we will re ommend that you use ve tors rather than arrays. We dis uss ve tors in
Chapter 20.
Even though we would like you to use ve tors eventually, we will study arrays at some length
for two reasons. First, the basi features of ve tors are also present in arrays. So what you
learn in this hapter will be useful later too. In addition, the working of an array is easier
to understand. Ve tors on the other hand, ontain some \hidden parts" so to say. Finally,
arrays are used substantially even today, and a knowledge of arrays is therefore useful.

13.1 Array: Colle tion of variables


C++ allows us to write statements su h as:
int ab [1000℄;

215
Abhiram Ranade, 2013. Do not distribute 216
This single statement de nes 1000 variables! The rst of these is referred to as ab [0℄,
next as ab [1℄, and so on till ab [999℄. The olle tion of these 1000 variables is said to
onstitute the array named ab , and ab [0℄, ab [1℄, ..., ab [999℄ are said to onstitue the
elements of the array. Any identi er (Se tion 3.1.1) an be used to name an to array. What
is inside [ ℄ is said to be the index of the orresponding element. The term subs ript is also
used instead of index. It is important to note that indi es start at 0, and not at 1 as you
might be in lined to assume. The largest index is likewise one less than the total number of
elements. The total number of elements (1000 in the above example) is referred to as the
length or the size of the array. As we know, an int variable needs one word of spa e, so the
statement above reserves 1000 words of spa e in one stroke.
The spa e for an array is allo ated ontiguously in the memory of the omputer, in the
order of the index, i.e. ab [1℄ is stored in memory following ab [0℄, ab [2℄ following
ab [1℄ and so on.
You may de ne arrays of other kinds also, e.g.
float b[500℄; // array of 500 float elements.
You an mix up the de nitions of ordinary variables and arrays, and also de ne several arrays
in the same statement.
double , x[10℄, y[20℄, z;
This statement de nes variables , z of type double, and two arrays x, y also of type
double, respe tively having lengths 10, 20. Note that one variable of type double requires
2 words of spa e, so this statement is reserving 2 words ea h for , z, and respe tively
2  10; 2  20 words for x,y.
You may de ne arrays in the main program or inside fun tions as you wish. Note however,
that variables de ned inside fun tions are destroyed on e the fun tion returns. This applies
to arrays de ned in fun tions as well.
As per the C++ standard, the length of the array should be spe i ed in the de nition
using a onstant. However, also see Se tion 13.7.
13.1.1 Array element operations
Everything that an be done with a variable an be done with the elements of an array of
the same type.
int a[1000℄;
in >> a[0℄; // reads from keyboard into a[0℄

a[7℄ = 2; // stores 2 in a[7℄.

int b = 5*a[7℄; // b gets the value 10.

int d = g d(a[0℄,a[7℄); // g d is a fun tion as defined earlier.

a[b*2℄ = 234; // index: arithmeti expression OK


Abhiram Ranade, 2013. Do not distribute 217
In the rst statement after the de nition of a, we are reading into the zeroth element a[0℄
of a, just as we might read into any ordinary variable. You an also set the value of an
array element by assigning to it, as in the statement a[7℄=2;. The statement following
that, b=5*a[7℄;, uses the element a[7℄ in an expression, just as you might use an ordinary
variable. This is also perfe tly ne. Note that just like ordinary variables, an element must
have a value before it is used in an expression. In other words, it would be improper in the
above ode to write int b = 5*a[8℄; be ause a[8℄ has not been assigned a value.
Elements of an array behave like ordinary or s alar variables of the same type; so they
an be passed to fun tions just like s alar variables. Hen e we an write g d(a[0℄,a[7℄);
if we wish, assuming g d is a fun tion taking two int arguments.
In the last line in the ode the index is not given dire tly as a number, but instead an
expression is provided. This is a eptable. When the ode is exe uted, the value of the
expression will be omputed and will be used as the index. In the present ase, by looking
at the pre eding ode we know that b will have the value 10, and hen e a[b*2℄ is simply
a[20℄. So 234 will be stored in a[20℄.

13.1.2 A eptable range for the index


When using arrays in your programs, it is very important to keep in mind that the array
index must always be between 0 (in lusive) and the array size (ex lusive). For example, for
the array a are de ned above, a referen e a[1000℄ would be in orre t, be ause it is not in
the range 0 to 999. Likewise, a referen e a[b*200℄ would also be in orre t, be ause it is
really the referen e a[2000℄ given that b has value 10 in the ode above.
If su h referen es are present in your program, its behaviour annot be predi ted. The
program may generate wrong values, fail to terminate, or terminate with an error message.
Any one of these out omes is possible, and C++ does not say whi h will happen.
Simply put, it is vital that you, the programmer, make sure that array indi es are in the
required range. This is an extremely important requirement.
13.1.3 Initializing arrays
It is possible to ombine de nition and initialization. Suppose we wish to reate a 5 element
float array alled pqr ontaining respe tively the numbers 15, 30, 12, 40, 17. We ould do
this as follows.
float pqr[5℄ = {15.0, 30.0, 12.0, 40.0, 17.0};
In fa t, an alternate form is also allowed and you may write:
float pqr[℄ = {15.0, 30.0, 12.0, 40.0, 17.0};
in whi h the size of the array is not expli itly spe i ed, and it is set by the ompiler to the
number of values given in the initilizer list. You an of ourse mix de nitions of arrays with
or without initialization, and also the de nition of variables.
int x, squares[5℄ = {0, 1, 4, 9, 16}, ubes[℄={0, 1, 8, 27};
Abhiram Ranade, 2013. Do not distribute 218
This will reate a single int variable x, and two initialized arrays, squares of length 5, and
ubes of length 4.
Of ourse, it might be more onvenient to initialize arrays separately from their de ni-
tions, espe ially if they are large. So if we wanted a large table of squares, it might be more
onvenient to write:
int squares[100℄
for (int i=0; i<100; i++)
squares[i℄ = i * i;

13.2 Examples of use


The ommon use of arrays is to store values of the same type, e.g. velo ities of parti les,
marks obtained by students, lengths of roads, times at whi h trains leave, and so on. You
ould also say that an array is perfe t to store any sequen e x ; x ; : : : ; xn. Of ourse, sin e
1 2
array indi es start at 0 in C++, it is more onvenient to all the sequen e x ; x ; : : : ; xn ,
0 1 1
and then store xi in ith element of a length n array. As will be dis ussed in Se tion 14.1,
an array an be used to store text. An array an also be used to store a ma hine language
program: the ith element of the array storing the ith word of the program (Se tion 2.8). We
will see many su h uses in the rest of this hapter and the following hapters.
In this se tion we give some typi al examples of programs that use arrays. You will see
some standard programming idioms for dealing with arrays.
13.2.1 Notation for subarrays
It will be onvenient to have some notation to indi ate subarrays of an array. Thus, we will
use the notation A[i..j ℄ to mean elements A[k℄ of the array A where i  k and k  j . Note
that if i > j , then the subarray is empty.
This notation is only for onvenien e in dis ussions, it is not supported by C++ and
annot be used in programs.
13.2.2 A marks display program
Suppose a tea her wants to announ e the marks the students in a lass have got. One way
would be to put up a list on the s hool noti e board. Another possibility is as follows. The
tea her loads the marks onto a omputer. Then any student that wants to know his marks
types his roll number, and the omputer displays the marks. Can we write a program to
1

do this?
For simpli ity, let us assume that there are 100 students in the lass, and their roll
numbers are between 1 and 100. Let us also stipulate that the program must print out the
marks of ea h student whose roll number is entered, until the value -1 is supplied as the roll
number. At this point, the program must halt.
Many might not like the idea of displaying marks in publi . An exer ise asks you to add a password so
1
that ea h student an only see her marks.
Abhiram Ranade, 2013. Do not distribute 219
Clearly we should use an array to store the marks. It is natural to store the marks of the
student with roll number 1 in the 0th element of the array, the marks of student with roll
number 2 in the rst element, and in general, the marks of the student with roll number i
in the element at index i 1. So we an de ne the array as follows.
float marks[100℄; // marks[i℄ stores the marks of roll number i+1.
You are probably wondering whether we need to hange the program if the number of
students is di erent. Hold that thought for a while, we will dis uss this issue in Se tion 13.7.
Next we read the marks into the appropriate array elements.
for(int i=0; i<100; i++){
out << "Marks for roll number " << i+1 << ": ";
in >> marks[i℄;
}
Remember that when the statement in >> marks[i℄; is exe uted, the then urrent value
of i is used to de ide whi h element gets the value read. Thus in the rst iteration of the
loop i will have the value 0, and so what is read will be stored in marks[0℄. In the se ond
iteration i will have the value 1 and so the newly read value will be stored in marks[1℄, and
so on. Thus indeed we will have the marks of a student with roll number i+1 be stored in
marks[i℄ as we want.
In the last part of the program, students enter their roll numbers and we are to print
out the marks for the entered roll number. Sin e this is to happen till -1 is given as the roll
number, we learly need a while loop. There are various ways to do this, we hoose one with
a break, similar to Se tion 7.2
while(true){
out << "Roll number: ";
int rollNo;
in >> rollNo;

if(rollNo == -1) break;

out << "Marks: " << marks[rollNo-1℄ << endl;


}

Clearly, if you typed 35 in response to the query \Roll number: \, then you would want the
marks for roll number 35, and these would be stored in marks[34℄. But this is exa tly the
same element as what is printed, marks[rollNo-1℄.
The program given above will work ne, so long as the roll number given is either -1 or in
the range 1 through 100. If a number other than these is given, say 1000, the program will
attempt to read marks[999℄. As we said, this may result in some irrelevant data to be read,
or worse, the program may a tually halt with an error message. Halting is not a eptable
in this situation, be ause students oming later will then not be able to know their marks.
Fortunately we an easily prevent this. If the roll number is not in the given range, then we
an say so and not print any marks. So the ode should really be as follows.
Abhiram Ranade, 2013. Do not distribute 220
while(true){
out << "Roll number: ";
int rollNo;
in >> rollNo;

if(rollNo == -1) break;

if(rollNo < 1 || rollNo > 100)


out << "Invalid roll number." << endl;
else
out << "Marks: " << marks[rollNo-1℄ << endl;
}

13.2.3 Who got the highest?


Having read in the marks as above, suppose we wish to print out the roll numbers of the
student(s) who got the highest marks, instead of answering student marks queries.
What we want an be done in 2 steps. In the rst step we determine the maximum marks
obtained. In the se ond, we print out the roll numbers of all who got the maximum marks.
In Se tion 3.4.1 we have already dis ussed how to nd the maximum of the numbers read
from the keyboard. Now instead of getting the marks from the keyboard, we are required to
read them from the array. Basi ally, instead of reading from the keyboard, the rst element
will be obtained from marks[0℄, and subsequent elements by looking at marks[i℄, where i
has to go from 1 to 100. The ode for this is as follows.
float maxSoFar = marks[0℄;
for(int i=1; i<100; i++){ // i starts at 1 be ause we already took marks[0℄
if(maxSoFar < marks[i℄)
maxSoFar = marks[i℄;
}
The next step is to print the roll numbers of those students who got marks equal to maxSoFar.
This is easily done, we examine ea h marks[i℄, for all i as i goes from 0 to 99, and whenever
we nd marks[i℄ equalling maxSoFar, we print out i+1, be ause we stored the marks of roll
number i+1 at index i.
for(int i=0; i<100; i++)
if(marks[i℄ == maxSoFar)
out << ``Roll number `` << i << `` got maximum marks.'' << endl;

13.2.4 General roll numbers


In the ode above, we exploited the fa t that the roll numbers are onse utive. In general
this may not happen. Often, the roll number assigned to ea h student may en ode di erent
kinds of information, e.g. rst two digits are year of joining, another digit indi ates the
department to whi h the student belongs, and so on. Sometimes the roll number may also
ontain letters, though for simpli ity we will ignore this possibility.
Abhiram Ranade, 2013. Do not distribute 221
We onsider the marks display problem in this new setting. We will use an additional
array rollno in whi h to store the roll number, in addition to the array marks used above.
The tea her rst types in 100 pairs of number, ea h pair onsisting of a roll number and the
marks obtained by the student having that roll number. Our program must read in the roll
number and marks and store them in the arrays rollno and marks. In the se ond phase,
when a student types in a roll number, we must rst look for it in the array rollno. If it is
found, then we print the orresponding marks.
int rollno[100℄;
double marks[100℄;

for(int i=0; i<100; i++) in << rollno[i℄ << marks[i℄;

while(true){
int r; in >> r; // roll number whose marks are requested
if(r == -1) break;
for(int i=0; i<100; i++)
if(rollno[i℄ == r) out << marks[i℄ << endl;
}
This idea, s anning an array from the beginning to the end in order to determine if a ertain
element is stored in the array, is sometimes alled linear sear h.
The ode above is unsatisfa tory in two ways. First, if the given value r is not present
in the array, it would be polite to print a message to that e e t. Se ond, on e we nd r
at some index, there is no need to s an the remaining elements. Both these goals an be
a heived by repla ing the for loop above with the following.
int i;
for(i = 0; i<100; i++){
if(rollno[i℄ == r){ out << marks[i℄ << endl; break;}
}
if(i >= 100) out << "Invalid roll number.\n";
Note rst that we break out of the loop upon nding a mat h. Thus, if a mat h is found
the variable i (whi h has now been de ned outside the loop) will have a value less than
100. The he k at the end su eeds only if all 100 iterations were exe uted without nding
a mat h, i.e. if the roll number r is invalid.
13.2.5 Histogram
Our next example is tri kier, and it illustrates an important powerful feature of arrays.
Again, we have as input the marks of students in a lass. Assume for simpli ity that
the marks are in the range 0 through 99. We are required to report how many students
got marks between 0 and 9, how many between 10 and 19, how many between 20 and 29
and so on. As you might know, what we are asked to report is often alled a histogram in
Abhiram Ranade, 2013. Do not distribute 222
Statisti s .
2

We are required to report 10 numbers. So it ould seem natural to use an array of 10


elements. The 0th element of the array an be used to ount the number of marks in the
range 0-9, the rst element for the range 10-19 and so on. So in general we ould say ith
element of the array should orrespond to the range i*10 to (i+1)*10-1 (both in lusive).
So we all the array ount and de ne it as:
int ount[10℄; // ount[i℄ will store the number of marks in the range
// i*10 through (i+1)*10 -1.
Clearly, we should set the ounts to 0 at the beginning, and hange them as we read in the
marks.
for(int i=0; i<10; i++)
ount[i℄=0;
When we read the next mark, how do we de ide whi h ount to in rement? It is natural to
write something like the following.
for(int i=0; i< 100; i++){
float marks;
in >> marks;
if(marks <= 9) ount[0℄++;
else if(marks <= 19) ount[1℄++;
else if(marks <= 29) ount[2℄++;
else if(marks <= 39) ount[3℄++;
else if(marks <= 49) ount[4℄++;
else if(marks <= 59) ount[5℄++;
else if(marks <= 69) ount[6℄++;
else if(marks <= 79) ount[7℄++;
else if(marks <= 89) ount[8℄++;
else if(marks <= 99) ount[9℄++;
else out << "Marks are out of range." << endl;
}
This works, but there is a better way! Suppose we read a mark m, whi h ount should we
in rease? For this we simply need to know the tens pla e digit of m. As you might observe,
this is simply bm=10 , i.e. the integer part of m=10. But we an get the integer part by
storing into an integer variable! This is what the following ode does.
for(int i=0; i< 100; i++){
float marks;
in >> marks;
int index = marks/10;
In general a histogram is a ount of number of observations (marks, in our ase) falling in various ranges
2
of values (in our ase the intervals 0-9, 10-19 and so on). The ounts are often depi ted as a bar hart, in
whi h the height of the bars is proportional to the ount and width to the size of the range.
Abhiram Ranade, 2013. Do not distribute 223
if(index >= 0 && index <= 9) ount[index℄++;
else out << "Marks are out of range." << endl;
}
Note that this works only be ause all the ranges are of the same size. But this is very often
the ase when omputing histograms.
13.2.6 A taxi dispat h program
Suppose you are the Mumbai dispat her for the Mumbai-Pune taxi servi e. Your job is as
follows. Drivers of taxis that are willing to take passengers to Pune report to you and give
you their driver ID number and wait. Passengers who want taxis also report to you. When
a passenger reports, you he k if there are any waiting taxis. If there are, you assign the
taxi of the driver that reported to you the earliest. Clearly, on e a taxi has been given
to a passenger, you need not keep the orresponding ID number on your list. If no taxis
are available, you let the passenger know. You are not expe ted to keep tra k of waiting
passengers, though an exer ise asks you to do pre isely this. You may assume that at any
given point there will not be more than 100 taxis waiting for passengers. You are to write a
program whi h will help you dispat h taxis as required.
Let us make this more spe i . Suppose that the dispat her will type 'd' when a driver
arrives, followed by the driverID. Likewise when a ustomer arrives, the dispat her will type
' ', and expe t the program to print the ID of the assigned driver. Finally, to terminate the
program, we will have the dispat her type 'x' ( ommonly used as abbreviation of eXit).
Next we de ide what variables we might need and how we should be using them.
Clearly, we will need to store the IDs of the waiting drivers. It seems natural to use an
array, say driverID, to store these. Assume for simpli ity that the IDs are integers with 9
or fewer digits, i.e. that they will t in int. The size of the array an be a number larger
than the number of drivers we expe t will be waiting with us at any time. Most of the time
there will be fewer drivers waiting with us than the size of the array, so we presumably need
a variable nWaiting whi h will denote the number of waiting drivers.
We also need to somehow re ord the order in whi h the drivers arrived, be ause we want
to assign the next ustomer to the driver who has registered with us the earliest. A natural
way to do this is to store the earliest waiting driver at index 0, the next earliest at index 1,
and so on. The ID of the driver that arrived last would be at index nWaiting - 1.
If a new driver arrives, we an store his ID at the index nWaiting, and in rement
nWaiting. If a ustomer arrives, we an assign the driver at driverID[0℄. However, on e
we assign the driver, we must shift up all the other entries in the array, sin e we have de ided
that the waiting drivers must be stored starting at index 0. This is expressed in the following
ode.
onst int n = 100; // estimate of max waiting drivers.
int driverID[n℄, nWaiting = 0;

while(true){ /* Invariants: nWaiting denotes the number of waiting drivers.


0 <= nWaiting <= n. IDs of waiting drivers are in driverID,
from driverID[0℄ to driverID[nWaiting - 1℄ */
Abhiram Ranade, 2013. Do not distribute 224
har ommand; in >> ommand;
if( ommand == 'd'){ // driver arrives
if(nWaiting >= n) out << "Queue full.\n";
else{
in >> driverID[nWaiting℄;
nWaiting++;
}
}
else if( ommand == ' '){ // ustomer arrives
if(nWaiting == 0) out << "Nothing available. Try later.\n";
else{
out << "Assigning " << driverID[0℄ << endl;
for(int i=1; i < nWaiting; i++) // shift up waiting drivers
driverID[i-1℄ = driverID[i℄;
nWaiting--;
}
}
else if( ommand == 'x') break;
else out << "Illegal ommand.\n";
}
Note that we have added he ks to see if the array driverID is already full when a driver is
to be entered, and to see if there is at least one element in it when a ustomer arrives.
You might think that perhaps there should be a way to write the program without having
to shift up the entries in driverID when we assign the driver at index 0. Instead of moving
up the drivers in the array, ould we not adjust our notion about where the front of the
queue is? Indeed this will work. But it will need a bit more are. To do this right, perhaps
it is worth onsidering how we might have dispat hed taxis without omputers.
Dispat hing without omputers
It is always worth thinking about how any problem, in luding taxi dispat hing, might be
solved without omputers. Say the dispat her writes the driverID numbers on a bla kboard,
top to bottom, as the drivers report. When a driver arrives, we put down the number at the
bottom of the list. When a passenger omes in, the number at the top of the list is given to
the passenger, and then the number is erased.
For simpli ity, let us assume that our bla kboard an only hold 100 phone numbers.
Managing this spa e on the bla kboard turns out to be slightly tri ky. Suppose 60 drivers
report, and you write down their numbers, starting at the top. Suppose you next have 50
passengers, so you mat h them to the top 50 numbers, whi h you erase. At this point you
have only 10 numbers on the board, however, they are not at the top of the board, but
they start halfway down the board. Suppose now 60 more drivers report. You would pla e
40 of these numbers below the 10 you have on the board, and that would take you to the
bottom of the board. Where should you pla e the remaining 20? It is natural to start writing
numbers from the top again, as if the bottom of the board were joined to the top. Think of
the bla kboard as forming the urved surfa e of a ylinder! Thus at this point, you have 70
Abhiram Ranade, 2013. Do not distribute 225
0 front + nWaiting % n 0 0
Occupied
1 1 1
by numbers
Unused
front + nWaiting % n

front

Occupied
by numbers
Unused Unused

front+nWaiting % n

front
Unused Occupied
by numbers
n −1 n −1 n −1

(a) At the beginning (b) After some time (a) After more time

Figure 13.1: Snapshots of the board

numbers on the board. They begin at position 50 (the topmost position being 0), go to the
last position, 99. Then they \wrap around" so that the last 20 numbers o upy positions
0 through 19 on the board. Positions 20-49 are then unused. This should not onfuse us;
say we make a mark next to the rst waiting driver. When we assign a driver, we erase the
number from the board, and also shift the mark down one. This works ne so long as the
number of taxi drivers waiting at any time does not ex eed 100.
Emulating a bla kboard on a omputer
Our program will mirror the a tions given above. We do not shift drivers up when a driver
is assigned, instead we have a variable front, whi h will always ontain the index of the
element of driverID ontaining the earliest waiting unassigned driver. This performs the
fun tion of the mark that the dispat her pla es on the board.
If there are nWaiting drivers waiting for ustomers, their IDs will appear at positions
starting at front. We need to be slightly areful as we say this: how do we des ribe what
happens when the board lls to the bottom and the dispat her is for ed to write the numbers
starting at the top again? We would like to somehow say that index that omes \next" after
the last index n-1 (i.e. the \bottom \ of the board) is index 0 (i.e. the \top" of the board).
So instead of saying that the next index after front is front+1, we will say that it is
(front+1) % n. If front has some value i<n-1, then (front+1) % n is just i+1. However,
if front equals n-1, then (front+1) % n will indeed be ome 0 as we wish. Thus we will
simply require that if there are nWaiting drivers that are waiting, their IDs will be at indi es
front, (front + 1) % n, : : :, (front + nWaiting - 1) % n.
Next we onsider what a tions to exe ute when a driver arrives. As before, we a ept
the ID only if driverID is not full. The ID of the arriving driver must be added at the so
Abhiram Ranade, 2013. Do not distribute 226
as to not violate the property mentioned above, i.e. at position (front + Waiting) % n.
After that we must in rement nWaiting.
When a ustomer arrives, as before we rst he k if there are any waiting drivers. If there
are, we assign the driver at the front of the queue, i.e. driverID[front℄. We add one to
front to get to the next element of driverID. however, sin e we want to onsider the queue
to start again from the top, the addition is done modulo n. Finally, we must de rement
nWaiting.

onst int n = 100; // estimate of max waiting drivers.


int driverID[n℄, nWaiting = 0, front = 0;

while(true){ /* Invariants: nWaiting denotes the number of waiting drivers.


0 <= nWaiting <= n. IDs of waiting drivers are in driverID,
from driverID[front℄ to driverID[(front + nWaiting - 1) %n ℄.
0 <= front < n
*/
har ommand; in >> ommand;
if( ommand == 'd'){ // driver arrives
if(nWaiting >= n) out << "Queue full.\n";
else{
in >> driverID[(front + nWaiting) % n℄;
nWaiting++;
}
}
else if( ommand == ' '){ // ustomer arrives
if(nWaiting == 0) out << "Nothing available. Try later.\n";
else{
out << "Assigning " << driverID[front℄ << endl;
front = (front + 1) % n;
nWaiting--;
}
}
else if( ommand == 'x') break;
else out << "Illegal ommand.\n";
}

You might have noted that it was easy to write this program on e we de ided learly how
our variables would be used. This is often a good strategy in writing programs.
13.2.7 A geometri problem
Suppose we are given the positions of the enters of several ir les in the plane as well as
their radii. Our goal is to determine whether any of the ir les interse t. Let us say that the
ith ir le has enter (xi ; yi ) and radius ri , for i = 0; : : : ; n 1.
Whether a pair of ir les interse t is easy to he k: the ir les interse t if and only if the
distan e between their enters is smaller than or equal to the sum of their radii. In other
Abhiram Ranade, 2013. Do not distribute 227
words, ir le i and ir le j interse t if and only if:
q
(xi xj )2 + (yi yj )2  r i + r j
Or equivalently (xi xj ) +(yi yj )  (ri + rj ) . Thus, in our program we must e e tively
2 2 2

he k whether this ondition holds for any possible i; j , where of ourse i 6= j .


Here is how we an do this. We will use arrays x,y,r in whi h we will store the x,y
oordinates of the enter and the radius of the ir les. Spe i ally, the x oordinate of the
enter of the ith ir le will be stored in x[i℄, the y oordinate in y[i℄, and the radius in
r[i℄. We will then he k whether ea h ir le i interse ts with a ir le j where j>i.
int n=5; // number of ir les. 5 hosen arbitrarily.
float x[n℄, y[n℄; // oordinates of enter of ea h ir le.
float r[n℄; // radius of ea h ir le.

for(int i=0;i<n;i++) // read in all data.


in >> x[i℄ >> y[i℄ >> r[i℄;
// Find interse tions if any.
for(int i=0; i<n; i++){
for(int j=i+1; j<n; j++){
if(pow(x[i℄-x[j℄,2)+pow(y[i℄-y[j℄,2) <= pow(r[i℄+r[j℄,2))
// built in fun tion pow(x,y) = x raised to y.
out << "Cir les " << i << " and " << j << " interse t." <<endl;
}
}
Thus in the rst iteration of the outer for loop, we he k for interse tions between ir le 0
and 1; 2; 3; : : : ; n 1. In the se ond iteration, we he k for interse tions between ir le 1 and
ir les 2; 3; : : : ; n 1, and so on. Is this lear that we he k all pairs of ir les in this pro ess?
Consider the kth ir le and the lth ir le, k 6= l. Can we be sure that the interse tion
between them is he ked? Clearly, if k < l, then in the iteration of the outer for loop in
whi h i takes the value k, we will he k interse tions with ir les k + 1; k + 2; : : : ; n 1.
This sequen e will ontain l be ause k < l. Alternatively, suppose l < k. Then onsider the
iteration of the outer for loop in whi h i= l. In this iteration we will he k the interse tion
of ir le l with ir les l +1; : : : ; n 1. Clearly k will be in this sequen e be ause l < k. Thus
in either ase we will he k the interse tion between ir le k and ir le l, for every k; l.

13.3 The inside story


We now dis uss some details regarding arrays and array a esses. This will spe ially be useful
for understanding how we de ne fun tions for operating on arrays. To make the dis ussion
more on rete, suppose we have the following de nitions.
int p=5, q[5℄={11,12,13,14,15}, r=9;
float s[10℄;
Abhiram Ranade, 2013. Do not distribute 228
Say ea h variable of type int is most ommonly given 4 bytes of memory, and so is a float.
Thus we know the above de nitions will ause 4 bytes of memory to be reserved for p,
4  5 = 20 bytes for q, 4 for r, and 4  10 = 40 bytes for s. We have also said that the
memory given for an array is ontiguous. Thus, the memory for q will start at a ertain
address, say Q, and go on to address Q +19. The notion of addresses is as per our dis ussion
in Chapter 2 and Se tion 9.8. Consistent with this des ription, Figure 13.3 shows how spa e
might have been allo ated for these variables.
Next we onsider what happens when during exe ution we en ounter a referen e to an
array element, e.g. q[expression℄. How does the omputer know where this element is
stored? Of ourse, rst the expression must be evaluated. Suppose its value is some v.
Then we know that we want the element of q of index v. But be ause the elements are
stored in order, we also know that the element with index v is stored at Q + 4v, where Q
is the starting address for q. Thus if v = 3 then we would want q[3℄, whi h is stored from
Q + 12. In general, the v th element of an array whi h is stored starting at address A would
be at A + kv, where k is the number of bytes needed to store a single element.
So the important point is, that to get to an array element, the omputer must evaluate
the index expression, and even after the expression is evaluated it must perform the multi-
pli ation and addition to get the address A + kv. This is in ontrast to how the omputer
gets the address for an ordinary variable su h as p. In this ase, the omputer already knows
where it stored p, and so it an get to it dire tly. Do note however that the extra work
needed to gure out where the element is stored is independent of the length of the array.
13.3.1 Out of range array indi es
Suppose now that our program has a statement q[5℄=17;. Using the formula A + kv given
above, the omputer would try to store 17 in the int beginning at the address Q + 4  5 =
Q + 20. Noti e that this is outside the range of memory allo ated for q . In fa t, it is quite
possible, as shown in our layout of Figure 13.3, that r is given the memory Q + 20 through
Q + 23. Then the statement q[5℄=17 might end up hanging r! Likewise it is on eivable
that a statement like q[-1℄=30; might end up hanging p.
Suppose on the other hand, we wrote q[10000℄=18;. This would require us to a ess
address Q + 40000. It is on eivable that there isnt any memory at this address. Many
omputers have some ir uits to sense if an a ess is made to a non-existent address or even
some forbidden addresses. The details of this are outside the s ope of this book, but if
this happens, then the program might halt with an error message. In any ase, it is most
important to ensure that array indi es are within the required range.
13.3.2 The array name by itself
So far we have not said whether the name of an array an be used in the program by itself,
i.e. without spe ifying the index. It turns out that C++ allows this.
In C++, the name of an array by itself is de ned to have the value equal to the starting
address from where the array is stored. This is an important pla e where arrays work
di erently from ve tors, as we will see in Chapter 20.
Continuing our example of Figure 13.3, sin e the array q is stored starting at address Q,
Abhiram Ranade, 2013. Do not distribute 229

Address Allo ation


Q 5 :::
Q 4
Q 3 p
Q 2
Q 1
Q
Q+1 q[0℄
Q+2
Q+3
Q+4
Q+5 q[1℄
Q+6
Q+7
Q+8
Q+9 q[2℄
Q + 10
Q + 11
Q + 12
Q + 13 q[3℄
Q + 14
Q + 15
Q + 16
Q + 17 q[4℄
Q + 18
Q + 19
Q + 20
Q + 21 r
Q + 22
Q + 23
Q + 24
Q + 25 s[0℄
Q + 26
Q + 27
Q + 28 :::

Figure 13.2: Possible layout


Abhiram Ranade, 2013. Do not distribute 230
the value of the name q itself would thus be Q, and the value of s, Q +24. Sin e the variable
at address Q is q[0℄, of type int, it is natural to de ne the type of q to be pointer to int,
or address of int, or int*. In general, if an array ontains elements of type T, then its name
will have type T* or address of T or pointer to T.
Thus s would be of type address of float or pointer to float or float*, and would have
the value Q + 24.
It seems strange that the name of an array is only asso iated with the starting address,
and that the length of the array is not asso iated with the name. This is merely a matter of
onvenien e, and its utility will be ome lear in Se tion 13.4.
An important point to note is that the value asso iated with the name of an array, say q,
annot be hanged; it always means the address of q[0℄. In other words, you annot write
an expression su h as
q = ...; // in orre t if q is the name of an array
Su h expressions will be agged as errors by the ompiler.
13.3.3 [℄ as an operator
A further tri ky point is that C++ onsiders a referen e to an array element, su h as X[Y℄
to be an expression, with X,Y the operands, and [℄ the operator! The operation is de ned
3

only if X has the type \address of some type T", and Y is an expression that evaluates to a
value of type int. Suppose that X is of type address of type T, and Y does evaluate to int.
Then the expression X[Y℄ denotes the variable of type T stored at the address A + kv, where
A is the value of X, v the value of Y, and k is the number of bytes needed to store a single
element of type T.
You will realize that we are merely restating how we nd the element given the name
of the array and the index. But the restatement is more general: X does not need to be
the name of an array, it ould be any name whose type is \address of some type T". This
generalization will ome in useful in Se tion 13.4.
Just to drive home the point, onsider the following ode.
double speed[℄={1.25, 3.75, 4.3, 9.2};
double *s;
s = speed;
out << s[0℄ << endl;
s[1℄ = 3.9;
out << speed[1℄ << endl;
The rst point to note is that the assignment s = speed is very mu h legal, sin e speed is
of type double*, just like s. Thus after the assignment, s will have the same value as speed.
But then, the expressions s[j℄ will mean the same as speed[j℄.
Put di erently, the expression s[0℄ denotes the double value stored at the address s +
k*i, where k is the size of double, and i the value of index, whi h are respe tively 8 and 0.
Yes, this is an unusual way of writing a binary expression. But do note that there are other operations
3
whi h are not written in the order operand1 operator operand2. For example, we often write ab rather than
a . b
Abhiram Ranade, 2013. Do not distribute 231
In other words, s[0℄ means the double stored at address s whi h is the same as speed, and
hen e is the same as the value stored at address speed, and so is speed[0℄. Thus the rst
print statement will print 1.25. The statement s[1℄ is likewise equivalent to speed[1℄, i.e.
to 3.9, whi h is what the se ond print statement will print.

13.4 Fun tion Calls involving arrays


Fun tions are onvenient with ordinary, or s alar variables, and indeed we an imagine that
they will be onvenient with arrays as well. Suppose we have an array of oats de ned as
float a[5℄; and somewhere in the program we need to al ulate the sum of its elements.
It is not diÆ ult to write the ode to ompute the sum of the elements of an array, however,
if the sum is needed for several su h arrays in our ode, then will have to repli ate the ode
that many times. So it would be very onvenient to write a fun tion whi h takes the array
as the argument and returns the sum.
As it happens, we have told you everything you need to write the fun tion! Here is what
you ould write.
float sum(float* v, int n){ // fun tion to sum the elements of an array
float s = 0;
for(int i=0; i<n; i++)
s += v[i℄;

return s;
}

We will explain this shortly. First we show how this fun tion might be alled from a main
program.
int main(){
float a[10℄ = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0}, asum;
asum = sum(a, 5); // se ond argument should be array length
}
Let us rst he k whether the fun tion all is legal, i.e. whether the types of the arguments
mat h those of the parameters in the de nition in the fun tion sum. The rst argument to
the fun tion all is the array name a. We said that the type asso iated with the array name
is T*, if the elements in the array are of type T. Thus the type of a is float*. This indeed
mat hes the type of the rst parameter, v, in the fun tion de nition. The se ond argument,
5, learly has type int whi h mat hes the type of the se ond parameter n. Thus the all is
legal and we now think about how it exe utes.
When the all length(a, 5) is en ountered, as usual an area is reated for exe ution of
the fun tion sum. The values of the non-referen e arguments are opied. In the present ase,
none of the parameters are referen e parameters, and so the values of both arguments are
opied. The value of the rst argument, a, is the starting address, say A, of the array a in
memory. Thus v gets the value A. The value of the se ond argument is 5. Thus n gets the
Abhiram Ranade, 2013. Do not distribute 232
value 5. It is very important to note here that the ontent of all the lo ations in whi h the
array is stored are not opied, but only the starting address is opied.
The ode of the fun tion is then exe uted. The only new part is the expression v[i℄.
This is pro essed essentially a ording to the rule given earlier. We know that v has type
address of oat, and its value is A. So now the expression v[i℄ is evaluated as dis ussed in
the previous se tion, by onsidering [℄ to be an operator and so on. Instead of doing the
pre ise al ulation again, we merely note that the value of v[i℄ evaluated in sum must be
the same as the value of a[i℄ evaluated in the main program, be ause v has the same value
and type as a. Hen e, v[i℄ will in fa t denote the ith element of a. Be ause n has value
5, in the loop i will take values from 0 to 4. Thus a[0℄ through a[4℄ will be added as we
desired.
Some remarks are in order.
1. Another syntax an also be used to de lare parameters that are arrays, in this ase
arrays of float variables: float v[℄ { this dire tly suggests that v is like an array
ex ept that we do not know its length.
2. Fun tion sum does not really know that it is operating on the entire array. For example
the all sum(a,3) is also allowed. This would return the sum of the rst 3 elements of
a, sin e the loop in the fun tion will exe ute from 0 to 2.

3. Modifying the passed array is also possible. If your fun tion had a line at the end su h
as v[0℄=5.0;, that would indeed hange a[0℄. This is onsistent with the me hanism
we have dis ussed for evaluating expressions involving [℄.
13.4.1 Examples
Shown below are two simple examples of fun tions on arrays. The next se tions gives more
involved examples.
Our rst fun tion merely prints the values of the elements of a float array.
void print(float *a, int n){
for(int i=0; i< n; i++)
out << a[i℄ << endl;
}

This will print out the rst n elements of the array. Note that it is the responsibility of the
alling program to ensure that the an array is passed, and that the array has length at least
as mu h as the se ond argument.
Next, we present a fun tion whi h returns the index of an element whose value is the
maximum of all the elements in the array. Note the areful phrasing of the last senten e:
when we say \an element", we a knowledge the possibility that there ould be many su h
elements, and we are returning the index of only one of them.
The idea of the fun tion is very similar to what we did for nding the maximum marks
from the marks array in Se tion 13.2.3. We have a variable maxIndex whi h will return the
position of an element with the maximum value. We start by initializing it to 0, whi h is
equivalent to onje turing that the maximum appears in position 0. Next, we he k if the
Abhiram Ranade, 2013. Do not distribute 233
subsequent elements of the array are larger, if we nd an element whi h is larger, then we
assign its index to maxIndex.
int argmax(float marks[℄, int L)
// marks = array ontaining the values
// L = length of marks array. required > 0.
// returns maxIndex su h that marks[maxIndex℄ is largest in marks[0..L-1℄
{
int maxIndex = 0;
for(j = 1; j<L; j++)
if( marks[maxIndex℄ > marks[j℄) // bigger element found?
maxIndex = j; // update maxIndex.
return maxIndex;
}

We have given the name marks so that it is easy for you to see the similarity between this
ode and the ode in Se tion 13.2.3. But by itself this fun tion does not have anything
to do with marks. So if you write it independently some more appropriate name su h as
datavalues should be used instead of the name marks.

13.4.2 Summary
The most important points to note are as follows.
To pass an array to a fun tion, we must typi ally pass 2 arguments, the name of the
array, and the length of the array. This is to be expe ted, the name only gives the starting
address of the array, it does not say how long the array is. So the array length is needed.
The alled fun tion an read or write into the array whose name is sent to it. This is like
sending the address of one friend A to another friend B, Surely then B will be able to write
to A or visit A just as you an!
Finally, it is worth noting an important point. When we write a fun tion on arrays, it
may be onvenient to allow it to be alled with length spe i ed as 0. What should a fun tion
su h as sum to when presented with an array of zero length? It would seem natural to return
the sum of elements as 0. This is what our sum fun tion does. On the other hand, our
argmax fun tion requires that the length be at least 1. Su h (pre) onditions on a eptable
values of parameters should be learly stated in the omments.

13.5 Sele tion sort


We will onsider a problem dis ussed at the beginning of the hapter: given the list of marks,
print them out in the order lowest to highest. We ould ask that along with the marks, we
also print out the roll numbers, however, this is left for the exer ises.
We an a omplish our task in two phases. In the rst phase, we rearrange the element
values in a non-de reasing order, i.e. so that the values appearing at lower indi es are no
larger than those appearing at larger indi es. This operation is often alled sorting. This
is one of the most important operations asso iated with an array. We will present a simple
Abhiram Ranade, 2013. Do not distribute 234
algorithm alled Sele tion sort for this. Better algorithms will be given later. On e the
elements are arranged in a non-de reasing order, we an simply print out the array elements
by index, i.e. element 0, then element 1 and so on. This will ensure that the marks are
printed in non-de reasing order. For this, we an simply use the fun tion print de ned
earlier.
We use a fairly natural idea for sorting. We begin by looking for the largest value in
the array, and we move it to the last position, i.e. index n 1, where n is the length of
the array. Of ourse, position n 1 itself ontains a value, and we annot destroy that. So
we instead ex hange the two: the maximum value moves to the n 1th position and the
value in the n 1th position moves to wherever the maximum was present earlier. Next,
we nd the maximum value amongst elements in positions 0 through n 2. This maximum
is ex hanged with the element in position n 2. Thus we have the maximum and se ond
maximum at positions n 1 and n 2. In general, we pro eed in this manner, in a typi al
iteration, we will nd the maximum from the rst i values, and then ex hange that with
the value at the i-1th index. We will have i begin with the value n, and ount it down in
su essive iterations till we rea h 2.
For nding the maximum, it is onvenient to use the argmax fun tion de ned in Se -
tion 13.4.1. If we want the maximum from the rst i elements, we simply invoke it using i
as the se ond argument. As we noted there, argmax need not be passed the a tual length of
the array; if it is passed a smaller value i it will merely nd a maximum in the rst elements
and return its index. So the ode is quite obvious.
void SelSort(float data[℄, int n)
// will sort in NON-DECREASING order. different from above.
{
for(int i=n; i>1; i--){
int maxIndex = argmax(data,i); // Find index of max in data[0..i-1℄
float maxVal = data[maxIndex℄; // Ex hange elements at
data[maxIndex℄ = data[i-1℄; // index maxindex
data[i-1℄ = maxVal; // and index i-1.
}
}
It should be lear that the ode above is doing what we des ribed. It is instru tive to write a
loop invariant also: At the beginning of the iteration, the subarray data[i..n-1℄ ontains
largest values. At the beginning i=n and hen e the invariant is va uously true.
Suppose the invariant is true at the beginning of some iteration, we will prove that it
will also hold for the next. The rst statement of the loop nds the maximum in the rst i
elements, i.e. elements 0 through i-1. The last 3 statements ex hange this with the element
at index i-1. Thus at the end of the iteration, the subarray data[i-1..n-1℄ will ontain
the largest values. This establishes the invariant for the beginning of the next iteration.
13.5.1 Estimate of time taken
We will try to get a rough estimate of the time needed by Sele tion sort. By rough estimate
we merely mean whether the time is proportional to n, the number of elements being sorted,
Abhiram Ranade, 2013. Do not distribute 235
or their square and so on. Su h estimates annot be used to de ide how many se onds
will be needed to exe ute the program. However, if we know that one program sorts in
time proportional to n, and another in time proportional to n , then for large n, the rst
2

algorithm will be better. Usually, we are about the time taken only when the problem size,
n in this ase, is large. So our qualitative analysis, whether the time is proportional to n or
n is quite useful.
2

To analyze the time for SelSort we must rst analyze the time for argmax. The fun tion
argmax simply goes over the subarray on whi h it is alled and nds the maximum. It
examines every element and thus its time an be onsidered to be proportional to L, the
se ond argument. In sele tion sort, we merely all argmax several times, with the value of
the se ond argument being n; n 1; n 2 and so on till 2. Thus we an see that the time is
proportional to
Xi n =

n + (n 1) + (n 2) + : : : + 2 = i  n =2 2

i=2

Thus we estimate the time taken by Sele tion sort as being proportional to n , where n is 2

the length of the array being sorted.

13.6 Representing Polynomials


A program will deal with real life obje ts su h as stars, or roads, or a olle tion of ir les.
It might also deal with mathemati al obje ts su h as polynomials. How to represent poly-
nomials on a omputer andPiperform operations on them are therefore important questions.
A polynomial A(x) = i aix is ompletely determined if we spe ify the oeÆ ients
n
= 1 i

a ; : : : ; an . Thus to represent the above polynomial we will need to store these oeÆ ients.
=0
0 1
This most onveniently done in an array. We use an array a of length n and store ai in
4

a[i℄.
Next omes the question of how we operate on polynomials. It is natural to ask; suppose
we have two arrays representing two polynomials A(x); B (x). Can we onstru t the rep-
resentation of the polynomials C (x); D(x) obtained by adding and multiplying A(x); B (x)
respe tively?
First we know that the sum will have degree n 1 be ause the addends A(x); B (x) have
degree n 1. Thus the array that we an use to represent the polynomial C (x) must
be de ned as float [n℄. We also know that i = ai + bi. Thus we know how to set the
elements of the array as well.
for(int i=0; i<n; i++) [i℄ = a[i℄ + b[i℄;
Can we write this as a fun tion addp whi h adds two polynomials? The polynomials to be
added will be passed as arguments. What about the result polynomial? We ould allo ate a
new array inside the fun tion addp, but this array annot be returned ba k { it gets destroyed
There is a simple rule here { if a olle tion of obje ts is des ribed using one subs ript, use a one
4
dimensional array, whi h is what we have studied so far. If a olle tion of mathemati al obje t is des ribed
using two subs ripts, say the entries of a matrix, then we will need two dimensional arrays, whi h we will
see later.
Abhiram Ranade, 2013. Do not distribute 236
as soon as addp nishes exe ution. The orre t way to write this pro edure is to pass the
result array as well. Here is a program whi h in ludes the fun tion addp.
void addp(float a[℄, float b[℄, float [℄, int n){
// addends, result, length of the arrays.
for(int i=0; i<n; i++) [i℄ = a[i℄ + b[i℄;
}
We have assumed in the above program that the addend polynomials have the same degree.
This need not be the ase in general. But you should be able to modify the ode to handle
the general ase.
We next onsider the problem of omputing the produ t polynomial D(x) of our polyno-
mials A(x); B (x). As before, we will assume that both A(x); B (x) have degree n 1, and are
stored in arrays a, b of length n. The produ t will have degree 2n 2, and must therefore
be stored in an array d of length at least 2n 1.
To determine D(x), onsider how its oeÆ ients relate to those of A(x); B (x). When
A(x) and B (x) are multiplied, ea h term aj xj in the former will be multiplied with bk xk
in the latter, produ ing terms aj bk xj k . Thus, this will ontribute aj bk to dj k . Thus we
+
+
start by setting every oeÆ ient of D to 0, and then for all j; k ompute aj bk and add it the
oeÆ ient dj k . This gives us the fun tion.
+

void prodp(float a[℄, float b[℄, float d[℄, int n){


// a,b must have n elements, produ t d must have 2n-1.
for(int i=0; i<2*n-1; i++) d[i℄ = 0;
for(int j=0; j<n; j++)
for(int k=0; k<n; k++) d[j+k℄ += a[j℄*b[k℄;
}
To omplete the example, here is a main program whi h alls these fun tions.
int main(){
float a[5℄, b[5℄, [5℄, d[9℄;
for(int i=0; i<5; i++) in >> a[i℄ >> b[i℄;

addp(a,b, ,5);
prodp(a,b,d,5);

for(int i=0; i<5; i++) out << [i℄ <<' ';


out << endl;
for(int i=0; i<9; i++) out << d[i℄ <<' ';
out << endl;
}

13.7 Array Length and onst values


In the examples given above, we have expli itly written out numbers su h as 500,1000 to
spe ify the array length. Arrays will often be used in programs for storing a olle tion of
Abhiram Ranade, 2013. Do not distribute 237
values, and the total number of values in the olle tion will not be known to the programmer.
So you might onsider it more onvenient if we are allowed to write:
int n;
in >> n;
int a[n℄; // Not allowed by the C++ standard. But read on!
This ode is not allowed by the C++ standard. The C++ standard requires that the length
be spe i ed by an expression whose value is a ompile time onstant. A ompile time onstant
is either an expli itly stated number; or it is an expression only involving variables whi h
are de ned to be onst, e.g.
onst int n = 1000;

The pre x onst is used to say that n looks like a variable, and it an be used in all pla es
that a variable an be used, but really its value annot be hanged. So using a onst name,
arrays might be de ned as follows.
onst int NMAX = 1000; // onvention to apitalize onstant names.
int a[NMAX℄, b[NMAX℄;

So how do we use this in pra ti e? Suppose we want to de ne an array whi h will store the
marks of students. In this ase, the C++ standard will require us to guess the maximum
number of students we are likely to ever have, de ne an array of that size, and only use a
part of it. So we might write:
onst int NMAX = 1000;
int a[NMAX℄, b[NMAX℄, na tual;
in >> na tual;
assert(na tual <= NMAX);
In the rest of the ode, we remember that only the rst na tual lo ations of a and b are used,
and so write loops keeping this in mind. Note that it is possible that the user will type in a
value for na tual that is larger than NMAX. In this ase we annot run the program. If this
happens, the assert statement will ause the program to stop, and you will need to hange
NMAX, re ompile and rerun.

13.7.1 Why onst de larations?


The above ode ould also dire tly de ne int a[1000℄,b[1000℄; instead of using the onst
de nition. However, the ode as given is preferable if we ever have to hange the required
size, say we want arrays of size 2000 rather than 1000. If we had not used NMAX we would
have to hange several o urren es of 1000 to 2000; with the ode as given, we just need to
hange the rst line to onst int NMAX = 2000;
Abhiram Ranade, 2013. Do not distribute 238
13.7.2 What we use in this book
The GNU C++ ompiler that you invoke when you use the ommand s++ allows arbitrary
expressions to be spe i ed as length in an array de nition.
As you an see, this makes the ode mu h more ompa t and easier to understand at a
glan e. So in the interest of avoiding lutter, in the rest of the book, we will use arbitrary
expressions while spe ifying lengths of arrays. The ode we give will work with s++. If it
does not work for some other ompiler, the dis ussion above tells you how to hange it.

13.8 Con luding remarks


Arrays provide an easy way to store sets of obje ts of the same type.
It is worth thinking about how the index of an element gets used. Sometimes the index
at whi h an element is stored has no signi an e, as in the ir le interse tion problem. Or
sometimes we an make a part of the data be the index, as we did for the roll number in the
marks display problem. Similar was the ase for the histogram problem. In the taxi dispat h
problem, we used the index to impli itly re ord the arrival order of the taxis.
Suppose we want to look for elements satisfying a ertain property. One way to do so is
to s an through the array, one element at a time, and he k if the element has the required
property. We did this in the problem of printing roll numbers of students who had the
highest marks. This is a ommon idiom.
The idea of s anning through the array starting at index 0 and going on to the largest
index is also useful when we want to perform the same operation on every element, e.g. print
it. We used a somewhat ompli ated version of this in the ir le interse tion problem, where
we wanted to perform a ertain a tion not for ea h ir le, but for ea h pair of ir les.
Finally, in the taxi dispat h problem we built a so alled queue so that the elements left
the array in the same order that they arrived in. For this we maintained two indi es: where
the next element will be stored and whi h element will leave next. This is a very ommon
idiom, and you will see it, for example, in Exer ise 14.
Finally, remember that the index used for an array should be in range, i.e. between 0
(in lusive) and the array length (ex lusive). Having the index out of range is a ommon
ause of errors in programs involving arrays. So you should make sure that the index is in
the range. You ould also onsider he king this using assertions. For example if you have
an array x of length 200, whi h you are about to index using an index i, you ould onsider
pla ing an assertion:
assert((i >= 0) && (i < 200));

before writing x[i℄.

13.9 Exer ises


1. Suppose the roll numbers in the lass do not go from 1 to the maximum number of
students, but are essentially arbitrary numbers (be ause perhaps they identify the year
in whi h the student enters, or the program that the student belongs to, and so on).
Abhiram Ranade, 2013. Do not distribute 239
Write the marks display program for this ase. Assume that for ea h student rst the
roll number is typed in, and then the marks. Also assume that at the beginning the
number of students is given.
2. Write the program to display who got the maximum marks for the ase above, i.e.
when the roll numbers are arbitrary integers.
3. Suppose we want to nd a histogram for whi h the width of the intervals for whi h we
want the ounts are not uniform. Say ea h value is a real number between 0 (in lusive)
and 1 (ex lusive). Between 0 and 0.25, our intervals are of width 0.05, i.e. we want
a ount of how many values are between 0 and 0.05, then 0.05 and 0.1, and so on.
Between 0.25 and 0.75 our intervals are of width 0.025, i.e. we want to know how
many values are between 0.25 and 0.275, then 0.275 and 0.3, and so on. Finally,
between 0.75 and 1, our intervals are of width 0.05. Write a program that provides the
histogram for these ranges.
4. You are to write a program whi h takes as input a sequen e of positive integers. You
are not given the length of the sequen e before hand, but after all the numbers are
given, a -1 is given, so you know the sequen e has terminated. You are required to
print the 10 largest numbers in the sequen e. Hint: use an array of length 10 to keep
tra k of the numbers that are andidates for being the top 10.
5. Suppose in the previous problem you are asked to report whi h are the 10 highest
values in the sequen e, and how frequently they appear. Write a program whi h does
this.
6. Suppose we are given the x; y oordinates of n points in the plane. We wish to know
if any 3 of them are ollinear. Write a program whi h determines this. Make sure
that you onsider every possible 3 points to test this, and that you test every triple
only on e. The oordinates should be represented as floats. When you al ulate
slopes of line segments, be ause of the oating point format, there will be round-o
errors. So instead of asking whether two slopes are equal, using the operator ==, you
should he k if they are approximately equal, i.e. whether their absolute di eren e is
small, say 10 . This is a pre aution you need to take when omparing oating point
5

numbers. In fa t, you should also ask yourself whether the slope is a good measure to
he k ollinearity, or whether you should instead onsider the angle, i.e. the ar tangent
of the slope.
7. Write a program whi h takes as input two ve tors (as de ned in mathemati s/physi s)
{ represent them using arrays { and prints their dot produ t. Make this into a fun tion.
8. Suppose you are given the number n of students in a lass, and their marks on two
subje ts. Your goal is to al ulate the orrelation. Let xi ; yi denote the marks in the
two subje ts. Then the orrelation is de ned as:
P P P
n xi yi xi yi
p P P p P
n x2i ( xi ) n yi2
2
(P yi) 2
Abhiram Ranade, 2013. Do not distribute 240
Write a program that al ulates this. Note that a positive orrelation indi ates that
x in reases with y (roughly) { whereas negative orrelation indi ates that x in reases
roughly as y de reases. A orrelation around 0 will indi ate in this ase (and often in
general) that the two variables are independent. You may use the dot produ t fun tion
you wrote for the previous exer ise.
9. Suppose you are given the maximum temperature registered in Mumbai on Mar h 21
of ea h year for the last 100 years. You would like to know whether Mumbai has been
getting warmer over the years, as is generally believed. You would like to know from
your data whether this might be a reasonable on lusion. If you merely plot the data,
you will see that the temperatures u tuate apparently errati ally from year to year.
The weather is expe ted to behave somewhat randomly; what you want to know is
whether there is any upward trend if you an somehow throw out the randomness.
One way to redu e the randomness is to smooth the data by taking so alled moving
averages. Given a sequen e of numbers x ; : : : ; xn , a 2k +1-window size moving average
1
is a sequen e of numbers yk ; : : : ; yn k, where yi is the average of xi k ; : : : ; xi k . Write
+1 +
a program whi h takes a sequen e and the integer k as input, and prints out the 2k +1
window-size moving average. Also plot the original sequen e and the moving average.
10. A sequen e x ; : : : ; xn is said to be a palindrome if xi = xn i for all i. Write
0 1 1
a program whi h takes a sequen e whose length is given rst and says whether the
sequen e is a palindrome.
11. The Eratosthenes' Sieve for determining whether a number n is prime is as follows. We
rst write down the numbers 2; : : : ; n on paper. We then start with the rst un rossed
5

number, and ross out all its proper multiples. Then we look for the next un rossed
number and ross out all its proper multiples and so on. If n is not rossed out in
this pro ess, then it must be a prime. Write a program based on this idea. Earlier in
the ourse we had a primality testing algorithm whi h he ked whether some number
between 2 and n 1 divided n.
12. Suppose we are given an array marks where marks[i℄ gives the marks of student with
roll number i. We are required to print out the marks in non-in reasing order, along
with the roll number of the student who obtained the marks. Modify the sorting
algorithm developed in the hapter to do this. Hint: Use an additional array rollNo
su h that rollNo[i℄ equals i initially. As you ex hange marks during the ourse of
the sele tion sort algorithm, move the roll number along with the marks.
13. Suppose you are given a sequen e of numbers, pre eded by the length of the sequen e.
You are required to sort them. In this exer ise you will do this using the so alled
Insertion sort algorithm. The idea of the algorithm is to read the numbers into an
array, but keep the array sorted as you read. In other words, after you read the rst i
numbers, you must make sure that they appear in the rst i elements of the array in
sorted (say non-in reasing) order. So when you read the i +1th number, you must nd
where it should be inserted. Suppose you dis over that it needs to be pla ed between
5 Well, Eratosthenes used a lay tablet!
Abhiram Ranade, 2013. Do not distribute 241
the numbers that are urrently at the j th and j + 1th position, then you should move
the numbers in positions j + 1 through i 1 (note that the indi es or positions start
at 0) forward in the array by 1 step. Then the newly read number an be pla ed in
the j + 1th position. Write the program that does this.
14. Suppose you are given two arrays A,B of lengths m,n. Suppose further that the arrays
are sorted in non-de reasing order. You are supposed to ll an array C of length m+n so
that it ontains pre isely the same numbers whi h are present in A,B, but they must
appear in non-de reasing order in C. In other words, if A ontains the sequen e 1,2,3,3,5
and B ontains 2,4,6,7, then C should ontain 1,2,2,3,3,4,5,6,7. Hint: Clearly, elements
must move out of A and B into C. Can you argue that for the purpose of this movement
all arrays behave like queues, i.e. elements always move out from the front of A,B, and
move into the ba k of C?
15. A friend (\the magi ian") shows you a de k of ards. He pi ks up the top ard, turns
it fa e up, and it is seen to be the a e. He puts the ard away. He then takes the next
ard and puts it at the bottom of the de k without showing it to you. Then he shows
you the ard now at the top of the de k, whi h turns out to be the 2. He repeats the
following pro ess until the de k has no ards. It turns out (magi ally!) that you see
the ards in in reasing fa e value, i.e. the rst ard to be exposed is the a e, then the
2, then the 3, then the 4, and so on until the King. Of ourse, the \magi " is all in the
order in whi h the ards were pla ed in the de k at the beginning. Write a program
that explains the magi , i.e. gures out the initial order of the ards and prints it.
Hint: Reverse the pro ess.
16. Write a fun tion whi h given polynomials P (x); Q(x) returns their omposition R(x) =
P (Q(x)). Say P (x) = x + 3x + 5 and Q(x) = 3x + 5x + 9. Then R(x) = (3x + 5x +
2 2 2

9) + 3(3x + 5x + 9) + 5.
2 2

17. Write the binary sear h ode without re ursion.


18. Consider a long railway tra k divided into some n parts of possibly unequal lengths.
For ea h ith part, you are given its length Li and a maximum speed si with whi h
trains an run on it. You are also given the data for a ertain lo omotive: its maximum
speed s and the maximum a ereration a it is apable of (assume this is independent
of the speed, for simpli ity), the maximum de eleration d (again independent of the
speed) it is apable of. Suppose the train starts at rest at one end of the tra k and
must ome to rest at the other end. How qui kly an the train omplete this journey?
Make sure your ode works for all possible values of the parameters.
19. A permutation is simply an ordering of the set of obje ts, say the numbers between 0
and n 1 for some n. It is often desirable to generate all possible permutations for a
given n. For example, for n = 3, we would like to generate a sequen e su h as
012
021
102
Abhiram Ranade, 2013. Do not distribute 242
120
201
210
The above sequen e is isn lexi ographi order, i.e. if you onsider ea h element to be
a digit in radix n, and on atenate the digits on atenate the sequen e and onsider
Let p be a permutation of integers from 0 to n 1 for some n. De ne V (p) to be the
integer obtained by on atenating the sequen e p. We will say that a permutation p
is lexi ographi ally smaller than another permutation q if V (p) < V (q). Modify it to
do so.
20. Write a program that takes a permutation p of integers from 0 to n 1 and returns
the lexi ographi ally next permutation. Hint: try out a few permutations to dedu e
the relationship between a permutation and the lexi ographi ally next permutation.
21. Write a program that takes in two numbers with 100 digits ea h, and prints out their
produ t. Adapt the polynomial multipli ation algorithm dis ussed in the text.
Chapter 14

More on arrays

We begin by onsidering the problem of representing textual data. In hapter 3 we dis ussed
the har datatype for storing hara ters. However, we rarely work with single hara ters.
More often, we will need to manipulate full words, or strings/sequen es of hara ters. A
hara ter string is ustomarily represented in C as an array of hara ters. This representation
is not quite re ommended in C++, as we will see in Se tion 20.1. But it is worth knowing this
representation be ause you will en ounter it be ause of lega y reasons (e.g. Se tion 14.3.1)
and be ause the C++ re ommended representation builds upon this.
Next, we dis uss multidimensional arrays. An ordinary (one dimensional) array an
be thought of as a sequen e of values. A two dimensional array an be thought of as a
matrix or a table (rows and olumns) of values. Two dimensional arrays are very useful,
espe ially in s ienti omputation. We will dis uss an important use of two dimensional
arrays: representing and solving linear systems of equations. C++ allows us to build our
own representations for two dimensional arrays whi h have all features we dis uss in this
hapter, and some additional ones. This is dis ussed in Se tion 20.2.6.
So far we have been exe uting C++ programs by writing a.out or ./a.out. However,
it is possible to supply input to the program on the ommand line itself, e.g. by writ-
ing a.out input-text. This requires the use multidimensional arrays, and is dis ussed in
Se tion 14.3.1.
Finally, we dis uss the use of re ursion in problems involving arrays. Suppose a problem
is given to you involving data stored in an array of length n. You an solve it using re ursion
if the following hold.
1. If n is small, say n = 1, then you have a way of solving the problem.
2. If n is not small, say n > 1, you have a way to onstru t problem(s) of the same kind,
on smaller arrays su h that from the solution to the smaller problem(s) you will be
able to onstru t a solution to the original problem.
If you an do these steps, then you have a re ursive algorithm. Often, su h re ursive algo-
rithms are very simple to state and ode, and also fast. We will see two su h algorithms, one
for the so alled Binary sear h algorithm, and another for Merge sort, whi h is an algorithm
for sorting.

243
Abhiram Ranade, 2013. Do not distribute 244
14.1 Chara ter strings
An array of hara ters an be de ned just as you de ne arrays of doubles or ints.
har name[20℄, residen e[50℄;

The above de nes two arrays, name and residen e of lengths 20 and 50, ostensibly for
storing the name and the residen e. Sin e we will usually not know the exa t number of
hara ters in a name or in an address, it is ustomary to de ne arrays of what we guess
might be the largest possible length. This might seem wasteful, and it is, and we will see
better alternatives in later hapters.
So if we want to store a hara ter string \Shivaji" in the array, we will be storing 'S' in
name[0℄, 'h' in name[1℄ and so on. The string is 7 hara ters long, and you would think that
we should store this length somewhere. While printing the string for example, we learly do
not want the name[7℄ through name[19℄ printed. The onvention used in the C language,
and inherited into C++ from there, is that instead of storing the length expli itly, we store
a spe ial hara ter at the end of the a tual string. The spe ial hara ter used is the one
with ASCII value 0, and this an be written as 'n0'. Note that 'n0' is not printable, and is
not expe ted to be a part of any real text string. So it unambiguously marks the end of the
string.
Spe ial onstru ts are provided for initializing hara ter arrays. So indeed we may write
har name[20℄ = "Shivaji";
har residen e[50℄ = "Main Pala e, Raigad";

The hara ter string \Shivaji" has 7 hara ters. So these will be pla ed in the rst
7 elements of name. The eighth element, name[7℄ will be set to 'n0'. Similarly only 20
elements of residen e will be initialized, in luding the last 'n0'. Note by the way that
apital and small letters have di erent odes.
Here is an alternative form.
har name[℄ = "Shivaji";
har residen e[℄ = "Main Pala e, Raigad";

In this, C++ will al ulate the lengths of name and residen e. Following the previous
dis ussion, these will be set to 8 and 20 respe tively.
We an manipulate strings stored in har arrays by going over the elements in a for loop,
for example.
14.1.1 Output
Printing out the ontents of a hara ter array is simple. Assuming name is a hara ter array
as before,
out << name;
Abhiram Ranade, 2013. Do not distribute 245
would ause the ontents of name from the beginning to the 'n0' hara ter to be printed on
the s reen.
The general form of the above statement is:
out << harptr;
where harptr is an expression whi h evaluates to a pointer to a har type. If name is a
hara ter array, then name indeed is of type pointer to har. This statement auses hara ters
starting from the address harptr to be printed, until a 'n0' hara ter is en ountered. Thus
hara ter arrays passed to fun tions an be printed in the expe ted manner.
14.1.2 Input
To read in a string into a har array you may use the analogous form:
in >> harptr;
Here harptr ould be the name of a har array, or more generally, an expression of type
pointer to har. The statement will ause a whitespa e delimited string typed by the user
to be read into the memory starting at the address denoted by harptr. After storing the
string the 'n0' hara ter will be stored. Here is an example.
har name[20℄;
out << "Please type your name: ";
in >> name;
The se ond statement asks you to type your name and the third, in >> name; reads in
what you type into the array name. The following points are worth noting:
1. From what you type, the initial whitespa e hara ters will be ignored. The hara -
ter string starting with the rst non-whitespa e hara ter and ending just before the
following whitespa e hara ter will be taken and pla ed in name. Thus if I type
Abhiram Ranade

with some leading whitespa e, the leading whitespa e will be dropped and only "Abhiram"
would go into name. Next, following "Abhiram" a null hara ter, i.e. 'n0' would be
stored. Thus the letters 'A' through 'm' would go into name[0℄ through name[6℄,
and name[7℄ would be set to 'n0'. Note that all this is very onvenient in that the a
single statement reads in all the hara ters, and further the 'n0' is also automati ally
pla ed after the last hara ter read in.
2. This way of reading in text is not useful if the text ontains spa es. Thus in the above
example, \Ranade" would not be read in into name. For that it is ne essary to use the
getline ommand dis ussed below.
3. This statement is potentially unsafe. In the above example if the user had typed in
more than 20 hara ters without a whitespa e in between, all those would be stored
starting at name[0℄. Thus the hara ters read in would be stored past the end of the
designated array name, possibly writing into memory that might have been allo ated
for some other variable.
Abhiram Ranade, 2013. Do not distribute 246
The safe alternative to this is to use the following ommand.
in.getline(x,n);
where x must be a name of a har array, or more generally a pointer to har, and n an
integer. This will ause whatever the user types, in luding whitespa e hara ters, to be
pla ed starting from the address x, until one of the following o urs
 A newline hara ter is typed by the user. In this ase all hara ters upto the newline
1

are opied into memory starting from the address x. The newline hara ter is not
opied. It is dis arded.
 n-1 hara ters are typed without a newline. In this ase all the hara ters are pla ed
into memory starting from address x, followed by a 'n0' hara ter.
As you may guess, it is ustomary to use the length of x as the argument n. So for example
we an write:
har name[20℄;
in.getline(name,20);
In this ase at most 19 hara ters that the user types will be opied, and we will have no
danger of over owing past the array limit.
14.1.3 Chara ter array pro essing
Chara ter arrays behave like ordinary integer arrays, ex ept when it omes to reading and
printing, and in that they ontain a 'n0' hara ter whi h marks the end of the useful portion
of the array. So pro essing them is reasonably straight forward. Note that hara ters are
a subtype of integers, and as su h we an perform arithmeti on hara ters, and ompare
them, just as we do for integers.
Our rst example is a fun tion for determining the length of the text stored in a har
array.
int length( har *txt){
//pre ondition: txt points to sequen e of '\0' terminated hara ters.
int L=0;
while(txt[L℄ != '\0') L++;
return L;
}
The fun tion takes a single argument, say the array name (or the pointer to the zeroth
element of the array). Noti e that the a tual length of the array is not needed. This is
be ause we a ess elements only till the null hara ter. Indeed, the fun tion simply steps
through the elements of the array, and returns the index at whi h it nds the null hara ter,
'n0'. Sin e the starting index is 0, the null hara ter will be at index equal to the length of
the text string.
1 On most modern keyboards this happens when you press the key labelled ENTER.
Abhiram Ranade, 2013. Do not distribute 247
Our se ond example is a fun tion for opying a string stored in an array sour e to another
array destination. This is like opying other arrays, ex ept that we must only worry about
the useful portion of the sour e array, i.e. till the o urren e of the 'n0' hara ter. The
fun tion does not worry at all about the lengths of the 2 arrays as de ned, it is assumed
that the all has been made ensuring that indi es will not ex eed the array bounds.
void s opy( har destination[℄, har sour e[℄)
// pre ondition: '\0' must o ur in sour e. destination must be long
// enough to hold the entire sour e string + '\0'.
{
int i;
for(i=0; sour e[i℄ != '\0'; i++)
destination[i℄=sour e[i℄;
destination[i℄=sour e[i℄; // opy the '\0' itself
}
As an example of using this, note that a string onstant an be used any pla e a pointer to
har is needed. Thus we an write s opy(name,"Einstein") whi h would simply set the
name to \Einstein".
Here is a more interesting fun tion: it takes two strings and returns whi h one is lexi o-
graphi ally smaller, i.e. would appear rst in the di tionary. The fun tion simply ompares
orresponding hara ters of the two strings, starting at the 0th. If the end of the strings is
rea hed without nding unequal hara ters, then it means that the two strings are identi al,
in whi h ase we must return '='. If at some omparison we nd the hara ter in one string
to be smaller than the other, that string is de lared smaller. If one string ends earlier, while
the pre eding hara ters are the same, then the string that ends is smaller.
This logi is implemented in the ode below. We maintain the loop invariant: hara ters
0 through i-1 of both arrays must be non null and identi al. So if we nd both a[i℄ and
b[i℄ to be null, learly the strings are identi al and hen e we return 0. If a[i℄ is null but not
b[i℄, then a is a pre x of b. Be ause pre xes appear before longer strings in the di tionary,
we return '<'. We pro eed similarly if b[i℄ is null but not a[i℄. If a[i℄>b[i℄ we return
'>', if a[i℄<b[i℄ we return '<'. If none of these onditions apply, then the ith hara ter
in both strings must be non-null and identi al. So the invariant for the next iteration is
satis ed. So we in rement i and go to the next iteration.
har ompare( har a[℄, har b[℄)
// returns '<' if a is smaller, '=' if equal, '>' if b is smaller.
{
int i = 0;
while(true){ // Invariant: a[0..i-1℄ == b[0..i-1℄
if(a[i℄ == '\0' && b[i℄ == '\0') return '=';
if(a[i℄ == '\0') return '<';
if(b[i℄ == '\0') return '>';
if(a[i℄<b[i℄) return '<';
if(a[i℄>b[i℄) return '>';
i++;
Abhiram Ranade, 2013. Do not distribute 248
}
}

This may be alled using the following main program.


main(){
har a[40℄, b[40℄;
in.getline(a,40);
in.getline(b,40);
out << a << " " << ompare(a,b) << " " << b << endl;
}
If you exe ute this program, it would expe t you to type two lines. Say you typed:
Mathemati s
Biology

then it would print out > and stop, be ause \Mathemati s" appears after \Biology" in the
di tionary order.
14.1.4 Address arithmeti
C++ programs pro essing har arrays often use arithmeti on addresses.
Suppose x is the name of an array of some type T. We have already said that x has value
equal to the address of the zeroth element of the array. Suppose further that i is an integer
expression. Then the expression
x+i
is valid in C++ programs, and has the value equal to the address of x[i℄. Note that in
general, a single element of type T may require some s bytes. Thus while x+i seems to be
adding i to the address x, the a tual value added is i*s be ause the address of x[0℄ and
of x[i℄ di er by i*s and not just i. Indeed, in general, if x is of type T*, then x+i is the
address obtained by adding i*s to the address denoted by x. Sin e this an be somewhat
onfusing, we have not dis ussed su h address arithmeti so far.
However, if x is of type har*, then s equals 1. In that ase, when we write x+i, we indeed
mean the address obtained by adding i. So perhaps for this reason, address arithmeti is
quite ommon in hara ter pro essing. Thus the s opy fun tion would more ommonly be
written as:
void s opy( har *destination, har *sour e){
while(*sour e != '\0'){
*destination = *sour e;
destination++;
sour e++;
}
Abhiram Ranade, 2013. Do not distribute 249
14.2 Two dimensional Arrays
Sequen es of numbers are naturally represented as arrays. However, we will run into obje ts
like matri es whi h are olle tions of elements des ribed using two indi es. For su h ases,
C++ provides two dimensional arrays.
Here is an example of how a two dimensional array might be de ned:
double a[m℄[n℄;

This auses spa e for m*n variables of type double to be allo ated. These variables are
a essed as a[i℄[j℄ where we require 0  i < m, and 0  j < n. The variables are stored
in the so alled row major order in memory, i.e. in the order a[0℄[0℄, a[0℄[1℄, ...
a[0℄[n-1℄, a[1℄[0℄, ... a[1℄[n-1℄, ... a[m-1℄[n-1℄. The numbers m,n are said
to be the rst and se ond dimension of the array. We will also refer to them as the number
of rows and the number of olumns respe tively.
Manipulating two dimensional arrays is similar to one dimensional { we ommonly use
a loop to go over ea h dimension. As an example, onsider the problem of multiplying two
matri es. Remember that if A is an m  n matrix, and B an n  p matrix, then there produ t
is an m  p matrix C where n
X
ij = aik  bkj
k =1

where we have let the array indi es start at 1, as is ustomary in Mathemati s. The ode
below, of ourse, starts indi es at 0. The ode also shows how a two dimensional array an
be initialized in the de nition itself if you wish. The values for ea h row must appear in
bra es, and these in turn in an outer pair of bra es.
double a[3℄[2℄={{1,2},{3,4},{5,6}}, b[2℄[4℄={{1,2,3,4},{5,6,7,8}}, [3℄[4℄;

for(int i=0; i<3; i++) // ompute = a * b.


for(int j=0; j<4; j++){
[i℄[j℄ = 0;
for(int k=0; k<2; k++)
[i℄[j℄ += a[i℄[k℄*b[k℄[j℄;
}

for(int i=0; i<3; i++){ // print out .


for(int j=0; j<4; j++) out << [i℄[j℄ << " ";
out << endl;
}
Abhiram Ranade, 2013. Do not distribute 250
14.2.1 Linear simultaneous equations
One of the most important uses of matri es and two dimensional arrays is to represent linear
simultaneous equations. Say we are given simultaneous equations:
3x + 5x = 10
2 3

2x + 6x + 8x = 38
1 2 3

7x + 4x + 9x = 22
1 2 3

Then they an be onveniently represented by the matrix equation


2
0 3 5 3 2 x 3 2 10 3 1
4 2 6 8 5 4 x 5 = 4 38 52
7 4 9 x 3 22
Denoting the matrix by A, the ve tor of unknowns by x and the right hand side ve tor by
b, we have the matrix equation Ax = b in whi h we are to solve for x given A; b.
The dire t way to solve a system of equations is by a pro ess alled Gaussian elimination ,
2

in fa t a form of it alled Gauss-Jordan elimination.


Observe rst that if the matrix A was the identity matrix, i.e. aii = 1 and aij = 0 for all
i; j 6= i, then the problem is very easy. Multiplying out we would get x = b. Thus for this
b is itself the solution. This suggests a strategy. We will make modi ations to A; b su h
that the modi ations do not hange the solution of Ax = b. If at the end of the sequen e
of modi ations, our matrix A be omes the identity matrix then the value of b at that time
would itself be the solution.
It turns out that several operations performed on the system of equations (and hen e
A; b) indeed do not hange the solutions to the system. One su h operation is to multiply
any equation by a onstant. This is akin to multiplying a row of the matrix A and the
orresponding element of the ve tor b by a (the same) onstant. Another operation is to add
one equation to another, and repla e the latter equation by the result. In our example, say
we add the rst equation to the se ond. Thus we get the equation 2x + 9x + 13x = 48.
1 2 3
We repla e the se ond equation with this equation. This is su in tly done in the matrix
representation: we merely add the rst row of A to the se ond row, and the rst element of
b to the se ond element of b. Thus the se ond row of A would then be ome [2 9 13℄ and the
se ond element of b would be ome 48, while the other elements remained the same.
We now show how we an hange A; b, without hanging the solution, so that the rst
olumn of A be omes 1,0,0 (read top to bottom), i.e. identi al to the rst olumn of the
identity matrix. The same pro ess an then be adapted for the other olumns.
1. If the oeÆ ient of x is zero in the rst equation, pi k any equation whi h has a non
1
zero oeÆ ient for x . Suppose the ith equation has a non-zero oeÆ ient for x . Then
1 1
ex hange equation 1 and equation i. This orresponds to ex hanging row 1 and row i
of A and also element 1 and element i of b. Doing this for our example we get:
2
2 6 8 3 2 x 3 2 38 3 1
4 0 3 5 5 4 x 5 = 4 10 5 2
7 4 9 x 223

2 The method is a tually mu h older than Gauss.


Abhiram Ranade, 2013. Do not distribute 251
2. Divide the rst equation by the oeÆ ient of a . We thus get
11
2
1 3 4 3 2 x 3 2 19 3
1
4 0 3 5 5 4 x 5 = 4 10 5
2
7 4 9 x 3 22
3. For ea h i, add ai times the rst equation to equation i. Say we do this for row 2.
1
Thus we must add a = 0 times the rst row. So nothing need be done. So we then
21
onsider row 3. Sin e a = 7, we add -7 times the rst equation to equation 3. Thus
31
we now have: 2
1 3 4 3 2 x 3 2 19 31
4 0 3 5 5 4 x 5 = 4 10 5
2
0 17 19 x 3 111
It should be lear that the above pro ess would indeed make the rst olumn identi al to
the rst olumn of the identity matrix. In a similar manner, you should be able to get the
other olumns to mat h the identity matrix.
The rst step in the above des ription deserves more explanation. Suppose you have
managed to make the rst j 1 olumns of A resemble the rst j 1 olumns of the identity
matrix. Now the rst step above instru ts you to nd an equation in whi h the oeÆ ient
of xj is non-zero. For this, you should only look at equations j through n, and not onsider
the rst j 1 equations. This step may or may not su eed. It will not su eed if akj = 0
for all k = j : : : n. In this ase, it turns out that the system of equations does not have a
unique solution; it may have many solutions or no solutions at all. In this ase you should
report failure.
The ode for doing all this is left as an exer ise.
14.2.2 Two dimensional har arrays
We may de ne two dimensional arrays of hars, with initialization, whi h is of ourse op-
tional. For example we ould write:
har ountries[6℄[20℄ = {"India","China","Sri Lanka","Nepal",
"Bangladesh","Pakistan"};
Here the rst string, "India" is deemed to initialize the zeroth row, and so on for the six
strings.
Applying only one index to the name of a two dimensional array returns the address
of the zeroth element of the orresponding row. For hara ter arrays, this is the way to
refer to one of the strings stored. Thus ountries[i℄ will return the address of the zeroth
hara ter of the ith string stored in the array, in other words, the address of the ith string.
So if we write ompare( ountries[0℄, ountries[1℄), where ompare is as de ned in
Se tion 14.1.3, it would return '<' as the result be ause India will pre ede Sri Lanka in the
di tionary order.
Here is a program whi h has two arrays, ountries whi h lists ountries, and apitals
whi h lists orresponding apitals. It takes as input a string from the keyboard. It prints
out the name of the orresponding apital if the string is in the list of ountries stored in
ountries. This he k is made using our ompare fun tion.
Abhiram Ranade, 2013. Do not distribute 252
int main(){
onst int wordLength = 20;
har ountries[6℄[wordLength℄ = {"India","China","Sri Lanka","Nepal",
"Bangladesh","Pakistan"};
har apitals[6℄[wordLength℄ = {"New Delhi","Beijing","Colombo","Kathmandu",
"Dhaka","Islamabad"};
har ountry[wordLength℄;
out << "Country: ";
in.getline( ountry,wordLength);

int i;
for(i=0; i<6; i++){
if( ompare( ountry, ountries[i℄) == '='){
out << apitals[i℄ << endl;
break;
}
}
if(i == 6) out << "Dont know the apital.\n";
}
When the loop terminates, we know that i must be stri tly less than 6 if the ountry was
found in ountries, and equal to 6 if not found. Hen e we print the message that we dont
know the apital only if i is 6 at the end.
14.2.3 Passing 2 dimensional arrays to fun tions
It is possible to pass a two dimensional array to a fun tion. However, in the alled fun tion,
the se ond dimension of the array parameter must be given as a ompile time onstant. Thus
we might write:
void print( har ountries[℄[20℄, int noOfCountries){
for(int i=0; i<noOfCountries; i++) out << ountries[i℄ << endl;
}
This may be alled as print( ountries,6), where the se ond argument is the rst dimen-
sion of the ountries array. It will print out the ountries on separate lines.
This is not too useful, be ause any su h fun tion an only be used for arrays in whi h the
se ond dimension is 20. For example, this makes it impossible to write a general matrix mul-
tipli ation fun tion for matri es of arbitrary sizes. This is a fundamental problem on erning
two dimensional arrays in the language C, whi h has been inherited into the language C++.
In Se tion 20.2.6 we will see how it an be over ome quite elegantly using the exible nature
of C++.
But if we do know the se ond dimension, then the standard two dimensional arrays are
useful. Here is how they an be used in drawing polygons in simple pp graphi s.
Abhiram Ranade, 2013. Do not distribute 253
14.2.4 Drawing polygons in simple pp
simple pp ontains the following ommand for drawing polygons:
Polygon pName( x, y,Verti es,n);
This will reate a polygon named pName. The parameters x, y give the rotation enter of
the polygon. The parameter n is an integer giving the number of verti es, and Verti es is
a two dimensional double array with n rows and 2 olumns, where ea h row gives the x,y
oordinates of the verti es, relative to the enter ( x, y). A polygon is a shape in the sense
of Chapter 5, so we may use all the ommands for shapes on polygons.
The boundary of the polygon is tra ed starting at vertex 0, then going to vertex 1 and
so on till vertex n-1 and then ba k to vertex 0. Note that the boundary may interse t itself.
Here is an example. We reate a regular pentagon and a pentagonal star. Then we rotate
them.
int main(){
initCanvas("Pentagon and Star");
double pentaV[5℄[2℄, starV[5℄[2℄;

for(int i=0; i<5; i++){


pentaV[i℄[0℄ = 100 * os(2*PI/5*i);
pentaV[i℄[1℄ = 100 * sin(2*PI/5*i);
starV[i℄[0℄ = 100 * os(4*PI/5*i);
starV[i℄[1℄ = 100 * sin(4*PI/5*i);
}

Polygon penta(200,200,pentaV,5);
Polygon star(200,400,starV,5);

for(int i=0; i<100; i++){


penta.left(5);
star.right(5);
wait(0.1);
}

getCli k();
}
Note that there is a more natural ways of spe ifying the star shape: onsider it to be a
( on ave) polygon of 10 verti es. Thus we ould have given the oordinates of the 10 verti es
in order. Cal ulating the oordinates of the \inner" verti es is a bit messy, though.

14.3 Arrays of Pointers


An array is really a sequen e in memory of variables of the same type. We have seen arrays
of int, double, har, but we an have arrays of any type of variable. So you might ask, an
we have arrays of pointers? It is ertainly possible, and it turns out to be useful too.
Abhiram Ranade, 2013. Do not distribute 254
We an reate an array of 10 variables, ea h of type pointer to int by writing the
following.
int *y[10℄;
This statement is undoubtedly onfusing. The way to understand it is to ompare it with a
usual array de nition.
int x[10℄;
You an read this statement as saying \x[i℄ is an int for i=0 to i=9." In a similar manner,
you should read the statement int *y[10℄; as saying \*y[i℄ is an int for i=0 to i=9."
But if ontent of y[i℄ is an int, then y[i℄ must be an int pointer.
On e you have de ned an array of pointers, you an store addresses of appropriate vari-
ables in ea h element of the array. For example, you might write something like:
int *y[10℄;
int z = 100;
y[0℄ = &z;
out << *y[0℄ << endl;

This will print 100, be ause y[0℄ ontains the address of z, and hen e *y[0℄ just means z,
and hen e the value of z, 100, will be printed.
We next dis uss an important use of arrays of pointers.
14.3.1 Command line arguments to main
So far, we have exe uted C++ programs by spe ifying the name of the exe utable le,
usually a.out, on the ommand line. Spe i ally, the program is exe uted by typing a.out
or ./a.out on the shell ommand line. This auses the main fun tion in your program to
be alled. But you may exe ute your program di erently. C++ does allow you to provide
additional text after a.out, and this text an be pro essed by your program. For example,
you may write:
./a.out Mathemati s Biology

In this ase your program an be told that you have typed the words Mathemati s and
Biology after a.out. This an be done using an alternative (overloaded) de laration pro-
vided for main.
int main(int arg , har *argv[℄);
Thus main may take two arguments. The rst is an integer argument arg . The se ond
argument is an array (sin e it ends in [℄) has name argv, and ea h element is of type har*.
In other words, argv is an array of pointers to har.
Suppose you use this form of main. Then when you exe ute your program, the Operating
System alls the fun tion main, but also passes some parameters. Spe i ally the following
are the values passed in the parameters:
Abhiram Ranade, 2013. Do not distribute 255
1. The parameter arg gives the number of words typed on the ommand line, in luding
the name of the exe utable program (a.out or other). Note that by \word" we simply
mean white spa e delimited sequen e of hara ters.
2. The parameter argv is an array of arg elements, with the ith element argv[i℄
being the address of the ith ommand line word (typi ally alled ith ommand line
argument).
Thus if you had invoked the main program by writing ./a.out Mathemati s Biology the
value of arg would be 3. The parameter argv would have 3 elements of type har*,
and these would respe tively be addresses of the text strings (null terminated) "./a.out",
"Mathemati s", and "Biology" respe tively.
Here is a simple program that just prints out the values of all its ommand line arguments.
int main(int arg , har *argv[℄){
for(int i=0; i<arg ; i++) out << argv[i℄ << endl;
}
This program when invoked as a.out Mathemati s Biology would print out
a.out
Mathemati s
Biology

Of ourse, you an do more interesting pro essing of the ommand line arguments. See
Appendix F.

14.4 Binary sear h


We often sort data be ause it looks ni e to print it that way. However, there is another
important motivation. Certain operations an be performed very fast if the data is sorted.
Suppose we have an array in whi h we have stored numbers. Suppose we are subsequently
given a number x and we are to determine if x is is present in the array. The natural strategy
is to go over ea h element in the array and he k if it equals x. In the worst ase we might
have to examine every array element.
We an adopt a leverer strategy if the array is sorted. Say our array is A and it ontains
size elements. Say A is sorted in non-de reasing order, i.e. A an ontain elements with the
same value, but they will o ur at onse utive indi es.
The basi idea is: instead of examining elements from the beginning of the array, in the
rst step we examine the element that is roughly in the middle of the array. Thus in the
rst step we he k if x < A[size/2℄. Here we mean integer division when we write size/2,
i.e. the value of size/2 rounded down. There are 2 ases to onsider.
The he k su eeds i.e. x is smaller than A[size/2℄. Now be ause the array is sorted,
we know that all elements in the subarray A[size/2+1..size-1℄ will also be larger
than x. Hen e x, if present in the array, will be in the portion A[0..size/2-1℄. Thus
using just 1 omparison, we have narrowed our sear h to the rst half of the array.
Abhiram Ranade, 2013. Do not distribute 256
The he k fails i.e. x is greater or equal to A[size/2℄. In this ase, we know that if x is
present in A, possibly several times, it must be present at least on e in A[size/2..size-1℄.
Thus the subsequent sear h needs to be made only in A[size/2..size-1℄.
Thus in both ases, after one omparison, we have ensured that subsequently we only need
to sear h in one of the halves of the array. But we an re urse on the halves!
The key question is: when does the re ursion end. Clearly, if our array has only one
element, then we should not try to halve it! In this ase we merely he k if the element
equals x and return the result of the omparison.
This gives us the following re ursive fun tion.
bool Bsear h(int x, int A[℄, int start, int size){
// x : target value to sear h
// range to sear h: A[start..start+size-1℄
// pre ondition: size > 0;
//
if(size == 1) return (A[start℄ == x);
int half = size/2; // 0 < half < size, be ause size>1.
if(x < A[start+half℄)
return Bsear h(x, A, start, half); // re urse on first half
else
return Bsear h(x, A, start+half, size-half); // re urse on se ond half.
}
There is an extra parameter, start whi h says where the subarray starts. So we are sear hing
in the region A[start...start+size-1℄. The \middle" element now is A[start+size/2℄
whi h is the same as A[start+half℄ in the ode. The \ rst half" starts at A[start℄ and
has size equal to half. The \se ond half" starts at A[start+half℄ and has size size -
half. Thus we have the re ursive alls in the fun tion.
Our ode might look \obviously orre t", but this is de eptive. Folklore has it that even
experien ed programmers make mistakes while writing binary sear h. So it is a good idea
to he k that our fun tion indeed works orre tly.
There are two aspe ts to working orre tly: the fun tion must terminate, and on termi-
nation return the orre t answer. We rst he k that the fun tion will indeed terminate.
Clearly, when size be omes 1, the fun tion will return. But note that if size > 1, the value
half = size/2 (integer division) is stri tly between 0 and size. Thus we an on lude that
half as well as size - half are both smaller than size. Hen e we have established that the
se ond parameter to Bsear h always redu es, and hen e must eventually be ome 1, where
upon the fun tion will return. That the orre t value is returned follows in the manner we
have argued above.
Here is a main program whi h tests our fun tion.
int main(){
onst int size=10;
int A[size℄={-1, 2, 2, 3, 10, 15, 15, 25, 28, 30};
for(int i=0; i<size; i++) out << A[i℄ << " ";
out << endl;
Abhiram Ranade, 2013. Do not distribute 257

for(int x=-10; x<=40; x++)


out << x << ": " << Bsear h(x, A, 0, size) <<endl;
}
We sear h the array for the presen e of every integer between -10 and 40. You will see that
1 is returned only for those integers that are present.
Noti e that the array is sorted, but ontains repeated values.
14.4.1 Estimate of time taken
Let us analyze a bigger example. Suppose we are he king for the presen e of a number in
an array of size 1024. How many array elements do we ompare in the pro ess?
The fun tion binsear h will rst be alled with the size parameter equal to 1024. When
we re urse, no matter how the omparison omes out, we will next all binsear h with size
512. Subsequently we all binsear h with size 256 and so on. Thus a total of 10 alls will
be made: in the last all size will be ome 1 and we will return the answer. In ea h all
we make only one omparison x < A[start+half℄, and hen e only 10 omparisons will be
made!
Compare this with the ase in whi h the array is not sorted: then we might have to make
as many as 1024 omparisons! Even if we agree that it takes a bit longer to all a fun tion,
alling binsear h 10 times (in luding the re ursion) will be mu h faster than having to
possibly ompare x with ea h of the 1024 elements. A tually, our binary sear h an be
3

written out as a loop, without re ursion, the exer ises ask you to do this.
In general you an see that for the re ursive algorithm the number of omparisons made
is simply the number of times you have to divide the size of the array so as to get the
number 1. This number is log n, if n denotes the size of the array. In other words, the time
is proportional to log n when we do Binary sear h.
2

In ontrast, if the array is not sorted, we are for ed to do linear sear h, in whi h ase the
2

we may need to ompare x to all the elements in the array, i.e. there ould be as many as n
omparisons.
Binary sear h is a simple but important idea. You will see that it will appear in many
pla es, perhaps slightly disguised, as it did in the Bise tion algorithm (Se tion 8.3) for nding
roots.

14.5 Merge sort


In Se tion 13.5 we saw the sele tion sort algorithm for sorting an array. In the worst ase,
sele tion sort will take time O(n ). In this se tion we will see the Merge sort algorithm whi h
2

will take time O(n log n). As you an see, log n is mu h smaller than n, and hen e n log n
is mu h smaller than n . Indeed if you ode up the two algorithms you will see that Merge
2 2 2
2

sort runs mu h faster.


If x is not present in the array, we will know that only after omparing it with all the 1024 elements.
3
If x is present, we will stop after we nd it. So in this ase, you ould say that \on the average" we will
ompare x with half the elements, i.e. we will do 512 omparisons.
Abhiram Ranade, 2013. Do not distribute 258
Merge sort is a re ursive algorithm. If we want to sort the sequen e S, we divide it into
two sequen es U and V of roughly equal size. We sort U,V, and then ombine the results to get
a single sorted sequen e. This is our nal result, the result of sorting S. Su h an algorithm is
also often alled a divide-and- onquer algorithm, be ause we divide S into smaller sequen es
whi h we sort ( onquer!) separately.
The division of S into U,V is simple: we just put the rst half of S into U and the se ond
half into V. The key question, of ourse, is how to ombine, or merge, the results of sorting
U and V. We will dis uss this rst, and then dis uss the entire algorithm.

14.5.1 A merging algorithm


Suppose we are given two rows of students, in ea h of whi h the students are arranged in
non-de reasing order of their height. Can we put them into a single row su h in whi h the
students will still be arranged in non-de reasing order? This problem is perhaps easier to
visualize, but as you an see it is the same problem as that of merging two sorted sequen es.
Here is a pro edure to merge the two rows u; v of students into a single row s. The rst
student in s should be the shortest of all students. The shortest in u is the student at the
front of u, and the shortest in v the student at the front of v. Thus the shortest overall must
be the shorter of the students at the front of u and front of v. So we an ask the shorter
of the two to leave his/her row, and join row s. Next, we have to nd the se ond shortest
student. Sin e the shortest student has moved to s already, the se ond shortest must be the
shortest from those that remain. So we again pi k the shorter of the students at the front of
the rows u; v, and send that student to the ba k of row s. For the third shortest, we merely
repeat the pro edure! Eventually, it might so happen that all the students in one of the rows
u; v have left for s. On e this happens, we ask the students from the remaining row to join
s, in the order they are standing in their row.
The analogy to the sorted sequen es U,V should be lear. In fa t, we will think of ea h
of the sequen es S,U,V as a queue, like the queue of drivers we had for the taxi dispat h
problem (Se tion 13.2.6). Drivers were joining that queue at the end, just as students/keys
will join S at the end. Drivers left from the front of the queue, and similarly in this ase
students/keys will leave U,V from the front. Thus the algorithm an be oded up as shown
in Figure 14.1. The omments in the ode explain the algorithm fully. As you an see, it
mat hes the student row merging pro edure dis ussed above. Also, you should be able to
prove the orre tness of the invariant given.
The fun tion Merge exe utes uLength + vLength iterations, i.e. as many as the total
number of keys. In ea h iteration a xed number of instru tions is exe uted. Hen e we an
say that the total time is at most some onstant times the number of keys, i.e. proportional
to the total number of keys.
14.5.2 Mergesort algorithm
Given a merge algorithm, the mergesort algorithm is easy. For sorting a sequen e S of length
n we pro eed as follows.
1. Create two smaller arrays of roughly half the size. Say array U of size n/2, and array
V of size n - n/2.
Abhiram Ranade, 2013. Do not distribute 259

void merge(int U[℄, int uLength, int V[℄, int vLength, int S[℄){
// arrays U,V of length uLength and vLength respe tively ontain the
// sequen es that are sorted. The result of merging is to be pla ed
// in the array S. The length of S is not spe ified expli itly, but
// it is assumed (pre ondition) to be uLength + vLength.

for(int uFront=0, vFront=0, sBa k=0; sBa k<uLength+vLength; sBa k++){


// INVARIANT: sBa k = uFront + vFront. Keys U[0..uFront-1℄ will
// have been moved to S, and and also keys V[0..vFront-1℄. S will
// ontain these keys in S[0..sBa k-1℄, in non-de reasing order.

if(uFront<uLength && vFront<vLength){ // if both queues non-empty


if(U[uFront℄ < V[vFront℄){ // if U has smaller
S[sBa k℄ = U[uFront℄; // move to S
uFront++; // advan e U
}
else{ // if V has smaller
S[sBa k℄ = V[vFront℄; // move to S
vFront++; // advan e V
}
}
else if(uFront < uLength) { // else if only U is not empty
S[sBa k℄ = U[uFront℄; // move to S
uFront++; // advan e U
}
else { // else if only V is not empty
S[sBa k℄ = V[vFront℄; // move to S
vFront++; // advan e V
}
}
}

Figure 14.1: The Merging algorithm


Abhiram Ranade, 2013. Do not distribute 260
2. Copy n/2 elements of S to U and the remaining n-n/2 elements to V.
3. Get the arrays U and V sorted. This requires a re ursive all for ea h.
4. Merge the arrays U and V ba k and put the result into the array S.
The ode for mergesort follows this outline exa tly.
void mergesort(int S[℄, int n){
if(n>1){
int U[n/2℄, V[n-n/2℄;
for(int i=0; i<n/2; i++) U[i℄ = S[i℄;
for(int i=n/2; i<n; i++) V[i-n/2℄ = S[i℄;

mergesort(U, n/2);
mergesort(V, n - n/2);
merge(U, n/2, V, n-n/2, S);
}
}
Note that we wrote the number of elements to be opied to U as n - n/2 and not n/2 in
order to a ount for the possibility that n might be odd.
We will now estimate the time T (n) taken by mergesort to sort a sequen e of length
n. Initially, we opy the elements of S to U,V. As dis ussed above this takes total time
proportional to at most n. After that we all mergesort re ursively. This takes time T (n=2)
and T (n n=2). Finally we all merge. The time taken by merge, we said is at most
proportional to n the total number of keys. Thus we have
T (n)  (Time proportional to n) + T (n=2) + T (n n=2)
where we have lubbed together the time to opy and time to merge as a single entry,
proportional to n. Suppose the onstant of proportionality is . Then we have
T (n)  n + 2T (n=2)
Here we have assumed for simpli ity that n is a power of 2, and hen e n n=2 = n=2.
Note that our inequality for T (n) is also valid if we substitute n=2 instead of n. Thus we
have T (n=2)  (n=2) + 2T (n=4), whi h we an substitute into itself! Thus we get
T (n)  n + 2T (n=2)  n + 2( (n=2) + 2T (n=4) = 2 n + 4T (n=4)
But we an ontinue in this manner till for k steps, where n = 2k . Thus we will get
T (n)  k n + 2k T (n=2k )
Sin e n=2k = 1 and k = log n, we have
2

T (n)  n log n + nT (1)


2

Noting that and T (1)  0 for some 0 , we get T (n)  n log n + 0n  00n log n for some
onstant 00 . Thus we have shown that T (n) is at most proportional to n log n.
2 2

2
Abhiram Ranade, 2013. Do not distribute 261
14.6 Exer ises
1. Write a program that reads in an integer from the keyboard and prints it out in words.
For example, on reading in 368, the program should print \three hundred and sixty
eight".
2. For this exer ise it is important to know that the odes for the digits are onse utive,
starting at 0. Further '8' - '0' is valid expression and evaluates to the di eren e in the
ode used to represent the hara ters, and is thus 8. To larify, if we exe ute
har text[10℄ = "1729";
int d = text[1℄ - '0';

Then d will have the value 7. Use this to write a fun tion that takes a har array
ontaining a number and return an integer of the orresponding magnitude.
3. Suppose destination and sour e are of type har*. What do you think the following
statement does?
while(*destination++ = *sour e++);

Note: it uses several programming idioms you have been warned not to use. The point
of this exer ise is not to en ourage the use of these idioms but to warn you how dense
C++ ode an be.
4. Extend the marks display program of Se tion 13.2.2 to use names rather than roll
numbers. At the beginning, the tea her enters the number of students. Then the
program must prompt the tea her to enter the name of the student, followed by the
marks. After all names and marks have been entered, the program then gets ready
to answer student queries. Students enter their name and the program prints out the
marks they have obtained.
5. Write a fun tion whi h takes a sequen e of parentheses, open and losed, of all types,
and says whether it is a valid parenthesization. Spe i ally, parentheses should be
in mat hing pairs, with the opening parenthesis before the losing, and if a pair of
parentheses ontains one parenthesis from another pair, then it must also ontain the
other parenthesis from that pair.
6. Write a \ al ulator" program that takes 3 ommand line arguments in addition to the
name of the exe utable: the rst and third being double values and the se ond being
a single har. The se ond argument must be spe i ed as an arithmeti operator, i.e.
+, -, * or /. The program must perform the required operation on the two numbers
and print the result.
7. Write a program that solves a system of n linear equations in n unknowns, based on
the dis ussion of Se tion 14.2.1. You should write
onst int n = 4;
Abhiram Ranade, 2013. Do not distribute 262
in your program and then subsequently de ne the arrays using n as de ned above.
This way it should be possible to use your program to solve systems of di erent size
simply by hanging the value of n.
8. Write a program that reads in a square matrix and prints its determinant. As above,
make the dimension of the matrix a onst int. You should NOT use the re ursive
de nition of determinant, but instead use the following properties:
 Adding a multiple of one row to another leaves the determinant un hanged.
 Ex hanging a pair of rows auses the determinant to be multiplied by -1.
 The deteminant of an upper triangular matrix (all zeros below the diagonal) is
simply the produ t of the elements on the diagonal.
If the rst element of the rst row is a zero, then ex hange rows so that it be omes non
zero. Then add suitable multiples of the rst row to the other rows so that the rst
olumn is all zeros ex ept the rst row. Similarly produ e zeros below the diagonal in
the se ond olumn, and so on.
9. Design an input instan e for the mergesort algorithm su h that every line of ode in
the merge algorithm of Se tion 14.5.1 will exe ute in one of the alls to merge.
10. Suppose you are given two sorted sequen es S; T of lengths m; n. Write a program that
nds the median of their union. You may nd it easier to write a program that nds the
ith smallest in the union, for general i. Hint: Compare the medians of the sequen es
S; T . What does the omparison tell you about the position of the ith smallest?
11. A very popular and elegant algorithm for sorting is the so alled Qui ksort. If A is the
sequen e to be sorted, this works as follows.
(a) Pi k a random element r of A.
(b) Constru t a sequen e S onsisting of all elements smaller than r.
( ) Constru t a sequen e L onsisting of the remaining elements.
(d) Sort the sequn es S; L (re ursively!) to produ e sequen es S 0; L0.
(e) Return the on atenation of sequen es S 0; L0.
Write the program for Qui ksort. By and large, Qui ksort works very fast. More
pre isely, it is possible to show that the expe ted time taken by Qui ksort (expe tation
al ulated over all random hoi es of r in all alls) is O(n log n). The proof of this is
outside the s ope of this book.
2

12. An interesting tri k is employed to make Qui ksort run fast. If the original sequen e A
is stored in the array A, then it is possible to ensure that steps 2,3 above will onstru t
S; L in A itself, with S pre eding L. This will ensure that the sorting step will also
produ e the result in-pla e, i.e. S 0; L0 will be produ ed in the same (sub)arrays as
were o upied by S; L. Thus the last step, on atenation, does not have to be done
expli itly. Here is how we an reate S; L inside A itself. Start s anning from A[0℄
Abhiram Ranade, 2013. Do not distribute 263
towards higher indi es. Stop when you nd a number A[i℄ larger than or equal to r.
Now start s anning ba kwards from the end, A[n-1℄. Stop when you nd A[j℄ smaller
than r. Ex hange the elements A[i℄,A[j℄. Clearly, A[0..i℄ and A[j..n-1℄ an be
onsidered parts of S,L. We an extend these by repeating the pro ess on the subarray
A[i+1..j-1℄.
Code up this idea. Write lear invariants to guide your ode. There is great potential
here for making silly mistakes!
13. You might have observed that most physi al obje ts are designed to have smoothed
rather than sharp orners. One way to smooth a orner is to lo ally ins ribe a ir ular
ar that is tangential to edges forming the orner. However, other urves are also often
used. One su h family of urves are the Bezier urves, whi h have been used in the
design of automobile bodies, for example. A Bezier urve of order n is a parametri
urve de ned by using n ontrol points p ; : : : ; pn. You will see that the urve is begins
1
at p and ends at pn and is smooth. The other ontrol points \attra t" the urve
1
towards them, but the urve need not pass through them.
The points on the urve are de ned using a parameter t whi h varies between 0 and
1, and for ea h value of t we get one point Bp ;:::;pn (t). This point an be determined
re ursively as follows. First, the base ase:
1

Bp (t) = p
To ompute Bp ;:::;pn (t), we rst determine points q ; : : : ; qn , where
1 1 1

qi = tqi + (1 t)qi
+1

i.e. qi is the point dividing the line segment pipi in the ratio t : 1 t. Now we have:
+1

1 Bp ;:::;pn (t) = Bq ;:::;qn (t)


1 1

Write a program whi h re eives points p ; : : : ; pn on the graphi s anvas and plots the
1
Bezier urve de ned by them. Vary t in the interval [0,1℄ in small steps, say  = 0:01,
and join Bp ;:::;pn (t) to Bp ;:::;pn (t + ) to get a urve. Experiment for di erent values
1 1
of n and positions of pi.
Chapter 15

Stru tures

An important problem in programming is how to represent the entities that are of interest
in the program. For example, in a program to manage a library, the important entities
might be the books and the library users. In a program about astronomi al al ulations,
the important entities might be the stars and the planets. Of ourse, you know in prin iple
how these entities are to be represented. Ea h entity has ertain attributes, e.g. books have
titles and authors, or stars have size, position, luminosity and possibly other attributes. You
simply need to de ne variables to hold all these attributes. However, for large programs,
there will be many, many variables, and managing them an be tiresome. Something like a
ling system might be useful. Presumably, we would like to organize related variables into
groups, and perhaps related groups into larger groups and so on. This ould ontrol the
lutter in our programs. This is indeed very desirable. In this hapter, we will see how it
an be done.
The fa ility we desire is super ially like an array; an array name does refer olle tively
to lots of elements; ex ept that now we want a name to refer to a olle tion of elements
whi h might be of di erent types. For example, for a book we might want the olle tion
to ontain the title, the name of the author, the pri e, the a ession number (the number
under whi h it is led in the library), information about who has borrowed it and so on. A
stru ture, as we will dis uss in this hapter, provides us what we want: it allows us to group
together data of di erent kinds into a single olle tion whi h we an olle tively refer to by
a single name. Using stru tures will turn out to be very natural for many appli ations.
We begin by dis ussing the basi ideas of stru tures. We will show several examples, and
then dis uss at length a stru ture using whi h 3 dimensional ve tors an be ni ely represented
and elegantly manipulated in programs. We will also revisit the taxi dispat h problem of
Se tion 13.2.6 and show how its program an be improved using a stru ture for representing
queues.

15.1 Basi s of stru tures


In C++ the word stru ture is used to denote a olle tion of variables. The variables in
the olle tion are said to be members of the stru ture. You an de ne di erent types of
stru tures, as per your need. For example, to store information about books, you might
de ne a stru ture type Book; you an spe ify that every stru ture of type Book should
264
Abhiram Ranade, 2013. Do not distribute 265
ontain members to store its name, title, pri e and so on.
A stru ture type an be de ned using a stru t statement as follows:
stru t stru ture-type {
member1-type member1-name;
member2-type member2-name;
...
}

This statement says that the name stru ture-type will denote a olle tion of variables or
members whose names and types are as given. The rules for hoosing names for stru ture
types or members are the same as those for ordinary numeri al variables, but it is often
ustomary to apitalize the rst letters of stru ture names, whi h is a onvention we will
follow.
As an example, here is how we might de ne a stru ture to store information about a
book.
stru t Book{
har title[50℄;
har author[50℄;
double pri e;
int a essionNo;
bool borrowed;
int borrowerNo;
};
Note that a stru ture de nition does not by itself reate variables or reserve spa e. But we
an use it to de ne variables (sometimes alled instan es, or obje ts) as follows.
Book pqr, xyz;
This statement is very similar to a statement su h as int m,n;. The statement int m,n;
reates variables m,n of type int. Likewise, the statement Book pqr, xyz; also reates
variables pqr,xyz, of type Book. As you might expe t, ea h of these variables is used for
storing the asso iated olle tion of members. Thus, ea h su h variable is allo ated as mu h
spa e as is needed to store the olle tion. Assuming 4 bytes are used to store an int and
8 for a double, we will need 16 bytes to store the members a essionNo, borrowerNo,
and pri e, and 50+50 bytes to store the members title and author. A bool data type
will typi ally be given 1 byte. So a total of 117 bytes has to be reserved ea h for pqr and
xyz. The number of bytes that e e tively get used might be larger, be ause there may be
restri tions, e.g. on many omputers it is ne essary that the starting address of a variable
must be a multiple of 4.
The word stru ture, or its short form stru t is often used to denote (a) a spe i variable
of a spe i stru ture type, e.g. the variable xyz above, or (b) a spe i stru ture type, e.g.
Book as de ned above, or ( ) the entire ategory of variables of any stru ture type. This is
similar to how we might use the word ower in every day onversation. It might mean the
spe i lotus whi h you have just plu ked, or a spe i type of ower, as in \a lotus is a
Abhiram Ranade, 2013. Do not distribute 266
ower", or the entire ategory of owers, as in \every ower is pretty in its own way". The
pre ise meaning will be lear from the ontext.
A member of a stru ture variable an be referred to by joining the variable and the
member name with a period, e.g. xyz.a essionNo. Su h referen es behave like variables
of the same type as the member, and so we may write:
xyz.a essionNo = 1234;
out << xyz.a essionNo + 10 << endl;
in.getline(pqr.title,50);
The rst statement will store the number 1234 in the member a essionNo of the variable
xyz. The se ond statement will add 10 to xyz.a essionNo, in whi h we just stored 1234.
Thus this statement will ause 1244 to be printed. In the third statement, the referen e
pqr.title refers to the rst of the two har arrays in pqr. Just as we an read a hara ter
string into a dire tly de ned har array, so an we into this member of pqr.
We an initialize stru tures in a manner similar to arrays. Assuming Book de ned as
above we might write
Book b = {"On Edu ation", "Bertrand Russell", 350.00, 1235, true, 5798};
This will opy elements of the initializer list to the orresponding members in the stru ture.
Here is a stru ture for representing a point in two dimensions.
stru t Point{
double x;
double y;
};
We may reate instan es of this stru ture in the manner des ribed before, i.e. by writing
something like Point p1;. We are allowed to have one stru ture be ontained in another.
Here for example is a stru ture for storing information about a ir le,
stru t Cir le{
Point enter;
double radius;
};
Now the following natural program fragment is quite legal.
Cir le 1;
1. enter.x = 0.5;
1. enter.y = 0.9;
1.radius = 3.2;
We ould also have a omplished this by initialization:
Cir le 1 = {{0.5,0.9},3.2};
One stru ture an be opied to another using an assignment. For example, assuming 1 is
as de ned above, we an further write:
Abhiram Ranade, 2013. Do not distribute 267
Cir le 2;
2 = 1;

This auses every member of 1 to be opied to the orresponding member of 2. In a similar


manner we ould also write:
Point p = 1. enter;
2. enter = p;
The rst statement opies every member of 1. enter to the orresponding members of p.
The se ond opies every member of p to the orresponding member of 2. enter.
We nally note that variables an be de ned in the same statement as the de nition of
the stru ture. For example, we ould have written
stru t Cir le{
Point enter;
double radius;
} 1;
whi h would de ne the stru t Cir le as well as an instan e 1.
15.1.1 Visibility of stru ture types and stru ture variables
If a stru ture type is going to be used in more than one fun tion, it must be de ned outside
both the fun tions. The de nition must textually appear before the fun tions in the le.
The rules for a essing stru ture variables are the same as the rules for variables of the
fundamental data types (Se tion 3.6). Thus in the blo k in whi h a variable is de ned, it
an be used anywhere following its de nition. Also, a name name de ned in blo k B might
shadow names de ned in blo ks that ontain B , or the name name might in turn be shadowed
by names de ned in blo ks ontained in blo k B .
15.1.2 Arrays of stru tures
Note that we an make arrays of any data type. For example, we ould make an array of
ir les or books if we wished.
Cir le [10℄;
Book library[100℄;
We an refer to members of the elements of the arrays in the natural manner. For example,
[5℄. enter.x refers to the x oordinate of the enter of the fth ir le in . Similarly
library[96℄.title[0℄ would refer to the starting letter in the title of the 96th book in
library.
Abhiram Ranade, 2013. Do not distribute 268
15.1.3 Pointers to Stru tures and ->
The \address of" operator & de ned in Se tion 9.8.1 and the dereferen ing operator * de ned
in Se tion 9.8.3 work as you might expe t with stru tures. Here is an example. Assuming
the de nition of Cir le as above, we might write
Cir le 1={{1,2},3}, * ptr;
ptr = & 1;
(* ptr).radius = 5;
The rst statement de lares ptr to be of type Cir le*, i.e. pointer to Cir les. The se ond
statement stores the address of 1 in ptr, whi h we often refer to as \sets ptr to point
to 1". The third statement dereferen es it so that * ptr really means 1, and then the
radius member of this is set to 5.
C++ provides the operator -> where x->y means (*x).y. Hen e (* ptr).radius ould
instead be written as ptr->radius, whi h you will agree is easier to read.
15.1.4 Pointers as stru ture members
It is possible to have pointers as members of a stru t. For example, we might have an
alternate way to represent stru tures as follows.
stru t Cir le2{
double radius;
Point * ptr;
}

where Point is as before. Thus we ould write


Point p1 = {10.0,20.0};
Cir le2 1, 2;
1.radius = 5;
2.radius = 6;
1. ptr = &p1;
2. ptr = &p1;
Thus we have reated 1 and 2 to be ir les of radii 5, 6 respe tively, both entered at
the point p1. Say we wanted to get the x oordinate of the enter. For this we would write
1. ptr->x, whi h would evaluate to 10.0 as you would expe t. Note further that if you
write
2. ptr->y = 25;
it would hange the y oordinate of p1, and hen e of the enter of both the ir les.
Abhiram Ranade, 2013. Do not distribute 269
15.1.5 Linked stru tures
Here is a tri kier example.
stru t Student{
int rollno;
Student* bestFriend;
};
The intention of the de nition should be lear; in ea h student stru ture, we wish to store a
pointer to the best friend of that student. But for this we have had to use the name Student
inside its own de nition! However it does not ause a problem. A pointer to a stru t
needs the same amount of memory no matter what is inside the stru t. Thus using the
new de nition we an allo ate memory for a Student obje t easily: we just need to allo ate
whatever is needed for an int and for a pointer. 1

We an use this to link students to their best friends as in the program below.
int main(){
Student s1, s2, s3;
s1.rollno = 1;
s2.rollno = 2;
s3.rollno = 3;
s1.bestFriend = &s2;
s2.bestFriend = &s3;
s3.bestFriend = &s2;

out << s1.bestFriend->rollno << endl;


out << s1.bestFriend->bestFriend->rollno << endl;
}

Thus after reating instan es s1, s2, s3, we set them respe tively to have roll numbers 1,
2, 3. Then we set s1's best friend to be s2, s2's best friend to be s3, and s3's best friend to
be also s2. Thus the rst print statement will print 2, while the se ond will print 3.
We will see detailed examples of su h linked stru tures later.

15.2 Stru tures and fun tions


It is possible to pass stru ture variables to fun tions. The key point to be noted is that the
name of a stru ture variable denotes the ontent of the asso iated memory, like ordinary
numeri al variable names, and unlike the name of an array, whi h denotes the address of
the asso iated memory. Thus stru tures behave like ordinary variables as far as passing to
fun tions and being returned from fun tions.
The following de nition is not allowed, of ourse:
1
stru t Studentf int rollno; Student friend; g;
This will require a Student obje t to ontain an internal Student obje t, and the internal Student obje t
to ontain a Student obje t, and so on. In other words we are de ning an in nite obje t! This is not allowed.
Abhiram Ranade, 2013. Do not distribute 270
We rst onsider an example for our Point stru ture as de ned above. The fun tion
below returns a Point that is the midpoint of the line joining two given points. It is followed
by a main program that uses it.
// Point as defined earlier
Point midpoint(Point a, Point b){
Point mp;
mp.x = (a.x+b.x)/2;
mp.y = (a.y+b.y)/2;
return mp;
}

int main(){
Point p1 = {0.0, 0.0}, p2 = {100.0, 200.0}, p3;
p3 = midpoint(p1, p2);
out << midpoint(midpoint(p1,p2), p2).x << endl;
}
The fun tion alls above exe ute essentially as per the des ription in Se tion 9.1. Consider
the all midpoint(p1,p2). First, an a tivation frame is reated. Then the values of the
arguments p1,p2 are opied to the orresponding parameters a,b in the a tivation frame.
Then the lo al variable mp is reated. Then its members x,y respe tively are set to the
averages of the orresponding members of a,b. Thus mp.x, mp.y will get the values 50,
100. Then, mp will be returned. Note that returning a stru ture means opying its value
to the main program. To re eive this value, in the main program a temporary variable of
type Point will be reated. After the returned value is pla ed in the temporary variable,
we are free to do whatever we like with it. In the se ond statement of the main program,
we are merely opying the value of the temporary variable to the variable p3. However, we
an do essentially everything with this variable that an be done using any variable. We
see this in the last statement. The all midpoint(p1,p2) will return the point (50,100).
The temporary variable whi h holds this is then passed as an argument to another all to
midpoint. This all will return the midpoint of the points (50,100) and (100,200). Thus it
will return the point (75,150). This point will be stored in a temporary stru ture, and nally
we take its x member, whi h gets printed. Thus 75 will get printed. 2

We an also use all by referen e (Se tion 9.7). Suppose we want to shift a given point
by some amount dx,dy in the x; y dire tions respe tively. Then the following fun tion is
natural to write.
void move(Point &p, double dx, double dy){
p.x += dx;
p.y += dy;
}
Noti e that we are passing the rst argument, the point, by referen e. Thus the point p in
the body will be deemed to refer to same variable that is passed as the rst argument in the
alling program. Thus the x,y members of that variable will get modi ed.
Note that temporary variables are reated also with ordinary numeri al variables. For example, when
2
you write a = z + sin(x)*y, temporary variables will be reated to hold the value of sin(x).
Abhiram Ranade, 2013. Do not distribute 271
15.2.1 onst referen e parameters
It is desirable to pass stru tures to fun tions by referen e even if we dont want them modi ed.
This is be ause when passed by value, the entire stru ture must be opied. Copying takes
time. This an be a signi ant overhead for a large stru ture su h as Book de ned above. 3

However, some subtle issues arise when passing parameters by referen e. For example,
suppose we passed the parameters to our midpoint fun tion by referen e as follows.
Point midpoint(Point onst &a, Point onst &b){
Point mp;
mp.x = (a.x+b.x)/2; mp.y = (a.y+b.y)/2;
return mp;
}
We have not only made the parameters be referen e parameters, but also de lared them
onst, i.e. asserted that they will not hange during exe ution. Sin e the fun tion midpoint
does not modify the points a,b, it is learly a good idea to de lare our intent expli itly
and mark the parameters onst. Indeed, if a parameter is marked onst, then it improves
readability be ause a human reader an tell at a glan e that it will not be modi ed.
However, the onst keyword serves another important purpose. Suppose we did not mark
the parameters onst. Then the rst all in our main program above, midpoint(p1,p2)
would be ompiled ne, but for the all midpoint(midpoint(p1,p2),p2) the ompiler would
ag an error! If a parameter is a non- onst referen e parameter, the ompiler assumes that
you wish to modify it in the ode. But if you wish to modify it, then the orresponding
argument must not be a ompiler generated temporary stru ture whi h is onsidered to
be a onstant. So if you do indeed pass a temporary stru ture su h as midpoint(p1,p2),
the ompiler suspe ts that you have perhaps made a programming error (over paranoidly,
perhaps) and tells you so. But if the parameter is marked onst, then the ompiler knows
that you are passing the parameter by referen e only to avoid opying.
15.2.2 Passing pointers to stru tures
Note nally that you an pass stru tures to fun tions using a pointer and then dereferen e
the pointer in the body to a ess the members of the stru ture. But it is onsidered better
to use referen es ( onst if appropriate).

15.3 Representing ve tors from physi s


In Chapter 17 we will see a program whi h deals with motion in 3 dimensional spa e. This
program will deal onsiderably with 3 dimensional ve tor quantities su h as positions, velo -
ities, and a elerations. So we will design a stru ture whi h makes it onvenient to represent
su h quantities.
A ve tor in 3 dimensions an be represented in many ways. For example, we ould
onsider it in Cartesian oordinates, or in so alled spheri al oordinates, or ylindri al
In addition, the a tivation frame of the alled stru ture will also have to have memory allo ated to store
3
the stru ture. This in reases the total memory requirement of the program.
Abhiram Ranade, 2013. Do not distribute 272
oordinates. For simpli ity, we onsider the rst alternative: Cartesian oordinates. Thus
we will have a omponent for ea h spatial dimension. Clearly our stru ture must hold these
3 oordinates. We will all our stru ture V3 and it an be de ned as:
stru t V3{
double x,y,z;
};
We should put this outside the main program. If the program is organized into many les,
this should go into a header le, whi h an then be in luded in all other les whi h need this
stru ture.
If our program uses 3 dimensional ve tors, very likely it will need to add su h ve tors, or
multiply su h a ve tor by a number. Here is a fun tion to add two ve tors. The resulting
ve tor is returned.
V3 sum(V3 onst &a, V3 onst &b){
V3 v;
v.x = a.x + b.x;
v.y = a.y + b.y;
v.z = a.z + b.z;
return v;
}
Noti e that we have made the parameters be referen e parameters to avoid opying, but also
made them onst sin e the parameters are not altered by the fun tion.
Next we have a fun tion to s ale up a ve tor by a numeri al fa tor.
V3 s ale(V3 onst &a, double fa tor){
V3 v;
v.x = a.x*fa tor;
v.y = a.y*fa tor;
v.z = a.z*fa tor;
return v;
}
It is also useful to have a fun tion that omputes the length of a ve tor.
double length(V3 onst &a){
return sqrt(a.x*a.x + a.y*a.y + a.z*a.z);
}

We an now use these fun tions to ompute the distan e s overed by parti le having initial
velo ity u, moving under onstant a eleration a after time t, as per the formula s = ut+ at ,
1 2

where it should be noted that s; u; a are ve tor quantities.


2

int main(){
V3 u,a,s;
double t;
Abhiram Ranade, 2013. Do not distribute 273
in >> u.x >> u.y >> u.z >> a.x >> a.y >> a.z >> t;
s = sum(s ale(u,t), s ale(a,t*t/2));
out << length(s) << endl;
}
This will indeed it will print the distan e overed as desired.

15.4 Taxi dispat h revisited


A stru t enables you to group together related variables and give them a name. A di erent
way to state this is: if some variables in your program are related, onsider putting them
into a suitable stru ture! By doing this, you are more learly expressing the relationships
between your variables, and thereby making your program easier to understand.
In the taxi-dispat h problem of Se tion 13.2.6, we mimi ked a bla kboard on whi h IDs
of waiting drivers would be written in real life. The bla kboard was not present in the
statement of the problem. But it was an important entity in the solution of the problem and
hen e, it is a good idea to use a stru t to represent it. We do this next.
The bla kboard was really doing the work of a queue in whi h we put in IDs of waiting
drivers. The term queue has a real life meaning: people wait in it and people leave from
it in the order in whi h they arrive. Likewise, IDs enter our bla kboard and then leave in
the same order. So we will all our stru t a Queue, whi h suggests its fun tion, rather
than alling it a bla kboard. Inside the stru t we will have as members all related variables,
driverID, front, nWaiting. Note however that queues an be used to represent other
entities besides waiting drivers, so for the array whi h held the IDs of the drivers we will
use the name elements rather than driverID. Likewise we will use the name QUEUESIZE to
denote the size of the array rather than the name MAXWAITING.
stru t Queue{
int elements[QUEUESIZE℄, nWaiting, front;
};
QUEUESIZE should be de ned earlier, say as
onst int QUEUESIZE = 100;
Grouping of related operations into a ni ely named fun tion also helps des ribe the intent.
Thus we should have fun tions whi h perform the work of inserting into the queue and also
removing from the queue.
bool insert(Queue &q, int value){
if(q.nWaiting == QUEUESIZE) return false; // queue is full
q.elements[(q.front + q.nWaiting) % QUEUESIZE℄ = value;
q.nWaiting++;
return true;
}
int remove(Queue &q){
if(q.nWaiting == 0) return -1; // queue is empty
Abhiram Ranade, 2013. Do not distribute 274
int item = q.elements[q.front℄;
q.front = (q.front + 1) % QUEUESIZE;
q.nWaiting--;
return item;
}
Note that we have passed the queue q by referen e, so that modi ations made to it are
visible ba k in the main program. Given these fun tions, the main program an be written
in a ni er manner than in Se tion 13.2.6.
int main(){
Queue q;
q.front = 0;
q.nWaiting = 0;
while(true){
har ommand; in >> ommand;
if( ommand == 'd'){
int driver; in >> driver;
if(!insert(q, driver)) out << "Cannot register.\n";
}
else if( ommand == ' '){
int driver = remove(q);
if (driver == -1) out << "No taxi available.\n";
else out << "Assigning: " << driver << endl;
}
}
}
This main program is easier to understand as ompared to the main program of Se -
tion 13.2.6. This is be ause it does not ontain mu h detail about how exa tly the waiting
IDs are stored in the queue. That detail is moved to the fun tions insert and remove.
These fun tions on the other hand are not on erned with how the queue is being used.
The two fun tions together guarantee that so long as the queue is a essed only using these
fun tions, we will get the expe ted behaviour: (a) whatever we insert into the queue will
be given ba k to us in a rst in rst out order, (b) we will not insert something when the
queue is already full, ( ) our a esses to the array q.driverID will not be out of range. So
although our ode has be ome a bit longer, we an see that ea h pie e is easier to understand
than the ompa t main program of Se tion 13.2.6.

15.5 Member Fun tions


We ould think of a stru ture as merely a me hanism for managing data; we organize data
into a olle tion rather than have lots of variables lying around. However, on e you de ne
a stru ture, it be omes natural to write fun tions whi h manipulate the data ontained in
the stru tures. You might say that on e we de ned V3, it is almost inevitable that we write
fun tions to perform ve tor arithmeti and ompute the Eu lidean length. On e we de ned
Abhiram Ranade, 2013. Do not distribute 275
Queue, it seemed quite natural to de ne fun tions insert and remove as well. Had we
de ned a stru ture to represent some other entity, say a book (in a library), we might have
found it useful to write a fun tion that performs the re ord-keeping needed when a book is
borrowed.
Indeed, you might onsider su h fun tions to be as important to the stru ture as are
members of the stru ture. So perhaps, should we make the fun tions a part of the stru ture
itself?
The de nition of stru tures you have seen so far really omes from the C language. In
the more modern de nition of stru tures, as it is in the C++ language, the de nition of
stru tures has been extended so that it an also in lude fun tions. At a high level, the more
general de nition of a stru ture is the same as before.
stru t stru ture-type {
member-des ription1
member-des ription2
...
}
But, now, a member-des ription may de ne a member-fun tion, in addition to being able
to de ne a data member as before.
We begin with an example. Here is an alternate way to write our stru t V3 and its main
program.
stru t V3{
double x,y,z;
double length(){ // member fun tion length
return sqrt(x*x + y*y + z*z);
}
V3 sum(V3 b){ // member fun tion sum
V3 v;
v.x = x + b.x; v.y = y + b.y; v.z = z + b.z;
return v;
}
V3 s ale(double t){ // member fun tion s ale
V3 v;
v.x = x*t; v.y = y*t; v.z = z*t;
return v;
}
void joker(double q){ // member fun tion, in luded for fun.
x = q;
out << length() << endl;
}
};

int main(){
V3 u, a, s;
Abhiram Ranade, 2013. Do not distribute 276
double t;
in >> u.x >> u.y >> u.z >> a.x >> a.y >> a.z >> t;
s = u.s ale(t).sum(a.s ale(t*t/2));
out << s.length() << endl;
}

We explain next how this ode works, i.e. how member fun tions an be de ned and used.
In general, the member-des ription of a member fun tion has the following form.
return-type fun tion-name (parameter1-type parameter1, parameter2-type
parameter2, ...) {body}
As you an see, the de nitions of sum, s ale and length all t in this form.
A member fun tion is expe ted to be alled on an obje t of the given stru ture type,
using the same \." notation used for a essing data members. We will use the term re eiver
to denote the obje t on whi h the member fun tion is alled. A simple example of a member
fun tion all is the expressions u.s ale(t) in the main program above, with u the re eiver.
The general form of the all is:
re eiver.fun tion-name(argument1, argument2, ...)
The exe ution of a all happens as follows.
1. The expressions re eiver, argument1, argument2, ... are evaluated.
2. An a tivation frame is reated for the exe ution.
3. The values of the arguments orresponding to the non referen e parameters among
argument1,... are opied over to the orresponding parameters.
4. The body of the fun tion is exe uted. Inside the body, the names of the data members
by themselves are onsidered to refer to the orresponding members of the re eiver.
Inside the body, we an thus read the values of the members of the re eiver, or also
modify the values if we wish. Note further that we may also use invoke member
fun tions on the re eiver, simply by alling them like ordinary fun tions.
We will soon dis uss how our main program will exe ute. However, rst we onsider a short
example.
V3 p = {1.0, 2.0, 3.0};
out << p.length() << endl;
p.joker(5);
out << p.x << endl;
When the all p.length() exe utes an a tivation frame is rst reated. Sin e there are no
arguments, there is nothing to be opied. So the body of the fun tion will start exe uting. In
the body, the names x,y,z will refer to the orresponding members of the re eiver, p. Thus,
the statement return
p sqrt(x*x + y*y + z*z); will return sqrt(1.0*1.0 + 2.0*2.0 +
3.0*3.0), i.e. 14. This will get printed.
Abhiram Ranade, 2013. Do not distribute 277
When the all p.joker(5) exe utes, an a tivation frame will again be reated. Then
the value of the argument, 5, will be opied to the orresponding parameter, q in the body
of the member fun tion joker. Then the assignment x=q will ause the member x of the
re eiver, in this ase, p, to be set to 5. Then there is a all to length. Sin e the fun tion
name appears by itself, i.e. not as r.length() for any r, it is deemed to refer to the re eiver
itself. Thus the length of p is al ulated. Note that the value of p.x has hanged
p to 5, and
hen e the length al ulated and printed will be p5  5 + 2  2 + 3  3 = 38. After this
the exe ution of p.joker will nish.
Finally, in the last statement, we will print the value of p.x. Note that 5 will get printed,
be ause this is what we set it to in the all p.joker(5).
The ode we have given in the main program at the beginning should now be understand-
able, ex ept perhaps for the expression u.s ale(t).sum(a.s ale(t*t/2)). This expression
should really be read as
(u.s ale(t)) .sum( (a.s ale(t*t/2)) )
Sin e u.s ale(t) returns a V3 obje t, we an invoke the member fun tion sum on it, passing
as the argument the V3 obje t returned by a.s ale(t*t/2).
15.5.1 Referen e parameters and onst
It is possible to make the parameters to member fun tions be referen e parameters. Indeed,
it is re ommended to do so, espe ially when the stru ture being passed is large. By passing
a stru ture by referen e, we avoid the overhead of opying it.
It is also good to add onst quali ers wherever possible. First, if any of the arguments
is not modi ed by the fun tion, then the orresponding parameter should also be de lared
onst. Se ond, if the re eiver is not modi ed by the fun tion, we an indi ate as mu h by
adding the keyword onst after the parameter list but before the body. The fun tion sum
above modi es neither its argument, nor its re eiver. Hen e it is better written as:
V3 sum (V3 onst &b) onst{ // noti e the two onst keywords
V3 v;
v.x = x + b.x; v.y = y + b.y; v.z = z + b.z;
return v;
}
We should similarly modify the member fun tions s ale and length.

15.6 Mis ellaneous features


15.6.1 Stati data members
Suppose you wish to keep a ount of how many Point obje ts you reated in your program.
Algorithmi ally, this is not diÆ ult at all; we merely keep an integer somewhere that is
initialized to 0, and then in rement it when we reate an obje t. The question is: how
should this ode be organized.
Abhiram Ranade, 2013. Do not distribute 278
First, we need to de ide where to pla e the ounter. It would seem natural that the
ounter be somehow asso iated with the Point type. This is indeed possible through the
use of stati data members, as follows.
stru t Point{
double x,y;
stati int ounter; // only de lares
Point(){
ounter++;
}
Point(double x1, double y1) : x(x1), y(y1){
ounter++;
}
};
int Point:: ounter = 0; // a tually defines

int main(){
Point a,b, (1,2);
out << Point:: ounter << endl;
}

A stati data member is a variable asso iated with a stru t type. It is de lared by pre xing
the keyword stati to the de laration. Note that while there will be a member x and a
member y in every Point stru ture reated through either of the onstru tors, there is only
one opy of the variable ounter. Inside the de nition of Point, the variable ounter an
be referred to by using the name ounter, outside the de nition a stati variable must be
referred to by pre xing its name by the stru t name and ::. So in this example we have
used Point:: ounter.
There is a subtlety asso iated with stati data members. The de nition of the stru ture
Point does not a tually reate the stati data variables; a stru t de nition is merely ex-
pe ted to reate a type, without allo ating any storage. Hen e we need the statement marked
\a tually defines" in the ode above.
15.6.2 Stati member fun tions
You an also have stati member fun tions. For example, in the above ode we ould have
added the following stati fun tion de nition of resetCounter to the de nition of Point.
stati void resetCounter(){ ounter = 0; } // note keyword ``stati ''
Stati member fun tions an be referred to by their name inside the stru ture de nition,
and by pre xing the stru ture name and :: outside the de nition. Further, stati member
fun tions are not invoked on any instan e, but they are invoked by themselves. So we an
write Point::resetCounter() in the main program if we wish to set Point:: ounter to 0.
Note that in non-stati member fun tions we use the names of the non-stati members
by themselves to refer to non-stati members of the re eiver, i.e. the obje t on whi h the
Abhiram Ranade, 2013. Do not distribute 279
non-stati member fun tion is invoked. However, for a stati member fun tion, there is no
re eiver. Thus it is an error to refer to non-stati members by themselves in the body of a
stati member fun tion.
15.6.3 The this pointer
Inside the de nition of any ordinary member fun tion, the keyword this is a pointer to the
re eiver. Normally, we do not need to use this pointer, be ause we an get to the members
of the re eiver by using the names of the members dire tly. However, it should be noted that
we ould use this too. Thus we ould have written the length member fun tion in V3 as
double length(){
return sqrt(this->x*this->x + this->y*this->y + this->z*this->z);
}
But of ourse this is not really a good use for this!
Suppose we wanted to have a member fun tion bigger in Cir le whi h would take
another Cir le and return the bigger of the two ir les. The fun tion would need to just
ompare the radii, and then return the ir le with the bigger radius. The following member
fun tion ode ould be added to the de nition of Cir le above.
Cir le bigger(Cir le ){
return (radius > .radius) ? *this : ;
}
We must return the re eiver if its radius is bigger than the radius of the argument ir le.
Thus we return *this.
15.6.4 Default values to parameters
Default values an be given, as for ordinary fun tions by spe ifying them as = value after
the orresponding parameter.

15.7 Exer ises


1. De ne a stru t for storing omplex numbers. De ne fun tions for arithmeti on
omplex numbers.
2. De ne a stru t for storing dates. De ne a fun tion whi h he ks whether a given date
is valid, i.e. the month is in the range 1 to 12, and the day is a valid number depending
upon the month and the year.
3. Write a fun tion whi h returns a ir le having two given points as the endpoints of a
diameter. Assume the de nition of the ir le stru ture given in Se tion 15.1.
4. De ne the operator >> for the lass V3. This should enable you to write in >> v;
where v is of type V3. When this is exe uted, the user will type in 3 oating point
numbers whi h will get pla ed in v.
Abhiram Ranade, 2013. Do not distribute 280
5. De ne a stru ture for representing omplex numbers. In addition to having a onstru -
tor whi h takes the real and imaginary parts as arguments, write a onstru tor whi h
will take as arguments r;  and returns a omplex number rei = r os  + i sin . Note
that this onstru tor annot have just two real arguments { that will lash with the
onstru tor taking real and imaginary parts as arguments. Add an optional argument,
say a bool type, whi h if spe i ed says whether the pre eding two arguments are to
be interpreted as real and imaginary parts or as r:.
6. De ne a stru ture for representing axis parallel re tangles, i.e. re tangles whose sides
are parallel to the axes. An axis parallel re tangle an be represented by the oordi-
nates of the diagonally opposite points. Write a fun tion that takes a re tangle (axis
parallel) as the rst argument and a point as the se ond argument, and determines
whether the point lies inside the re tangle. Write a fun tion whi h takes a re tangle
and double values dx,dy and returns a re tangle shifted by dx,dy in the x and y
dire tions respe tively.
7. De ne a stru ture lass for storing information about a book for use in a program deal-
ing with a library. The lass should store the name, author, pri e, a library a ession
number for the book, and the identi ation number of a library patron (if any) who
has borrowed the book. This eld, patron identi ation number ould be 0 to indi ate
that the book is not borrowed.
Read information about books from a le into an array of book obje ts. Then you
should enable patrons to issue and return books. When a patron issues/returns a book,
the patron identi ation number of the book should be hanged. Write fun tions for
doing this. The fun tions should he k that the operations are valid, e.g. a book that
is already re orded as borrowed is not being borrowed without rst being returned.
8. Write a program to answer queries about an estry. Your program should read in a le
that ontains lines giving the name of a person (single word) followed by the name of
the father (single word). Assume that there are at most 100 lines, i.e. 200 names. After
that, your program should re eive a name from the keyboard, and print all an estors
of the person, in the order father, grandfather, great grandfather and so on as known.
Adapt the ideas from Se tion 15.1.5.
Chapter 16

Classes: stru tures with a personality

When we design a stru ture-type, we often have a lear idea as to how the instan e stru tures
will be used. For example, onsider the Queue stru ture-type dis ussed in the last hapter.
We expe t that a Queue obje t will be reated, and we will set the data members nWaiting,
front to 0. Subsequently the member fun tions insert and remove will be alled to in-
sert and remove elements as needed. We also expe t that the data members will not be
independently modi ed, i.e. if q is an obje t of type Queue, you will not write something
like q.nWaiting = 50;. The member q.nWaiting will hange, but this will happen only
as a part of the exe ution of the member fun tions insert or remove. As designers of a
stru ture, it is perhaps desirable if we learly state how we expe t the stru ture to be used,
and perhaps also prohibit inappropriate uses. If we an do this, perhaps it would redu e
programming errors.
The situation is a tually quite similar to how ele tri al devi es are designed. For example,
a television omes with a ontrol panel on the front (or a remote ontrol) whi h helps you to
ontrol it. If you wish to hange the hannel or in rease the volume, you press the appropriate
buttons provided for that purpose. You do not need to open the ba kside and manipulate
any ele tri al omponent dire tly! In a similar manner, the users of the Queue stru ture
should be given an interfa e (like the ontrol panel) whi h tells them the fun tions using
whi h they an use the stru ture. Anything else, they should not be allowed to do. Users of
Queue should be on erned with the interfa e just as the users of television sets need only
know how to use the ontrol panel. The users of television sets need not know what is inside
the box; similarly, the users of Queue need not know pre isely how the fun tions provided do
their job, so long as they do what they promise. We dis ussed similar ideas in the ontra t
model for designing fun tions (Se tion 9.3).
C++ indeed allows designers to build stru tures whi h users must a ess only through
a arefully hosen set of fun tions (the interfa e), and whose internal details su h as data
members are hidden. In fa t, C++ allows stru ture designers glorious ontrol over the entire
life y le of the stru ture variables. Designers an pre isely ontrol how their stru ture
variables will be (a) reated, (b) used in assignments, ( ) used with di erent operators, (d)
passed to fun tions, (e) returned from fun tions, (f) and nally destroyed when needed. As
we have seen in the previous hapter, C++ already provides default me hanisms for (a), (b),
(d), (e), (f). But it turns out that we an hange those me hanisms to suit our needs.
Te hni ally, the term lass is essentially synonymous with the term stru ture, as we will

281
Abhiram Ranade, 2013. Do not distribute 282
see in Se tion 16.8. However in more ommon parlan e, the term stru ture is typi ally used
to mean what we de ned in Se tion 15.1. This is how stru tures originated in the C language.
The notion got extended in C++ to in lude member fun tions as dis ussed in Se tion 15.5,
and as will be further extended in this hapter. In ommon parlan e, the term lass is used
to mean the extended modern notion.

16.1 Constru tors


A onstru tor is a spe ial member fun tion that you an write in order to make it easier
to initialize, or even automate the initialization of a stru ture. We will show two examples
before dis ussing how onstru tors work in general.
stru t Queue{
int nWaiting, front, elements[QUEUESIZE℄;
Queue(){ // onstru tor begins
front = nWaiting = 0;
} // onstru tor ends
}
The above ode de nes the stru ture Queue and a onstru tor member fun tion for it. Given
this de nition, suppose we write
Queue q1, q2;
in the main program. It turns out that this statement will not only allo ate memory for
q, but also initialize q1.front, q1.nWaiting, q2.front and q2.nWaiting all to 0! As you
an see, this is very onvenient be ause we will never use a Queue without rst setting the
members front and nWaiting to 0. Given the above onstru tor, we dont have to worry
about forgetting to initialize the members.
Before we explain how onstru tors work, another basi motivation behind onstru tors
should be noted: as mu h as possible, outside of a stru ture de nition, we should a ess only
the member fun tions, and not refer to the data members dire tly. This is be ause fun tions
are de ned arefully by the designer having onsidered the proper ways of manipulating the
stru ture. So it is best to not dire tly a ess the data members. Also see Se tion 16.7.1. If
data members are not to be a essed outside the de nition, then the only way they an be
initialized is using a fun tion. A onstru tor is meant to be su h a fun tion.
In our next example we show two onstru tors for our lass V3 and their use.
stru t V3{
double x,y,z;
V3(double p, double q, double r){ // onstru tor 1
x = p;
y = q;
z = r;
}
V3(){ // onstru tor 2
x = y = z = 0;
Abhiram Ranade, 2013. Do not distribute 283
}
// des ription of other member fun tions omitted.
};

int main(){
V3 ve 1(1.0,2.0,3.0);
V3 ve 2;
}
The rst statement in the main program will reate a variable ve 1 of type V3, with its
x,y,z members set to 1.0, 2.0, 3.0 respe tively. The se ond statement will reate a variable
ve 2 of type V3 with its members set to 0, 0, 0. As you might guess, the initialization of the
two variables has somehow happened using our two onstru tors respe tively. We dis uss
the pre ise me hanism of all this next.
In general, a onstru tor is spe i ed as a member fun tion of the same name as the
stru ture type. Further, there is no return type. Here is the general form.
stru ture-type (parameter1-type parameter1, parameter2-type parameter2,
...){ body }
You an spe ify as many onstru tors as you want, so long as the list of parameter types are
di erent for ea h onstru tor.
Whenever a variable of stru ture-type is de ned in the program, memory is allo ated
for the variable, and then an appropriate onstru tor gets alled on the reated variable to
initialize it. Whi h onstru tor gets alled depends upon whether the name of the variable
in the de nition is followed by a list of arguments. If there is an argument list, then a
onstru tor with a mat hing list of parameters is sele ted. Thus, in ase of our de nition of
ve 1 above, there is a list with 3 double arguments. Hen e onstru tor 1 is sele ted. If no
argument list is given following the variable name, then a onstru tor all will be made with
no arguments, and so a onstru tor whi h an be alled without arguments is sele ted. In
the de nition of q1,q2 and ve 2 above, there is no argument list, and hen e the onstru tor
taking no arguments ( onstru tor 2 in ase of ve 2) is sele ted for initializing.
Next the sele ted onstru tor is alled on the variable to be initialized, using arguments
as appropriate. In other words, the variable to be initialized serves as the re eiver for the all.
This all exe utes like any member fun tion all, as des ribed in Se tion 15.5. Spe i ally,
an a tivation frame is reated and the argument values are opied to the parameters. Then
the body of the onstru tor is exe uted, with the re eiver being the variable to be initialized.
Let us now see what happens for the statement V3 ve 1(1.0,2.0,3.0); in our program
above. As we said, this would ause onstru tor 1 to be alled on ve 1 using the arguments
1.0, 2.0, 3.0. Thus in the exe ution an a tivation frame is reated and the argument values,
1.0, 2.0, 3.0 are opied to the orresponding formal parameters p,q,r. Then the body of
onstru tor 1 starts exe ution. The rst statement of the body, x = p; sets the x member
of the re eiver, ve 1, to the value of the parameter p. Similarly, the members y and z are
set to the values q and r respe tively. After this the onstru tor all ends. Thus at the end,
ve 1 will have its members x,y,z set to 1.0, 2.0, 3.0 respe tively. The statement V3 ve 2;
is exe uted similarly. It auses the se ond onstru tor to be invoked on ve 2. As you an
see, it will set all 3 members to 0. Similarly for the initialization of q1,q2.
Abhiram Ranade, 2013. Do not distribute 284
Note that if you want the onstru tor without arguments to be alled, you must not
supply any list of arguments; it is not orre t to supply an empty argument list. This
is be ause V3 ve 2(); is not the same as V3 ve 2;. The former means something quite
di erent: it de lares ve 2 to be a fun tion that takes no arguments and returns a result of
type V3, as we dis ussed in Se tion 11.2.1.
If one stru ture is nested inside another, then the onstru tor exe utes slightly di erently.
This and other nuan es are dis ussed in Se tion 16.1.4.
16.1.1 Calling the onstru tor expli itly
If a onstru tor is alled expli itly by supplying required arguments, it does result in the
reation of a temporary stru ture. Su h stru tures an be used in subsequent pro essing, as
dis ussed in Se tion 15.2.
V3 ve 3, ve 4;
ve 3 = V3(1.0, 2.0, 3,0);
ve 4 = V3();
In this ase, the all V3(1.0, 2.0, 3.0) will exe ute as follows. First a temporary (name-
less) variable of type V3 is reated. Then the onstru tor is alled on it with the given
arguments. As a result we have a temporary V3 stru ture whose members are set to 1.0,
2.0, 3.0 respe tively. This temporary stru ture an be used as we wish, in the above ode
its value is opied to the variable ve 3. The next statement likewise reates a temporary
stru ture with all members 0. This is opied to ve 4. Thus, after the exe ution of the ode
above, the variables ve 3 and ve 4 will have the same values as ve 1 and ve 2 earlier,
respe tively.
Using an expli it onstru tor all, we an write the sum member fun tion of Se tion 15.5
more ompa tly as follows.
stru t V3{
...members and onstru tors 1 and 2...
V3 sum (V3 b){
return V3(x+b.x, y+b.y, z+b.z);
}
}

16.1.2 Default values to parameters


Parameters to onstru tors an also be given default values. For example, we ould have
bundled our two onstru tors for V3 into a single onstru tor by writing
V3(double p=0, double q=0, double r=0){
x = p;
y = q;
z = r;
}
Abhiram Ranade, 2013. Do not distribute 285
Now you ould all the onstru tor with either no argument, or upto 3 arguments { parame-
ters orresponding to arguments that have not been given will get the default values, in this
ase 0. Note that if you in lude our new onstru tor in the de nition, you annot in lude
any of the onstru tors we gave earlier. Say you spe i ed the new bundled onstru tor and
also onstru tor 2. Then a all V3() would be ambiguous, it would not be lear whether
to exe ute the body of onstru tor 2, or the body of the new onstru tor in whi h all 3
parameters are initialized to their spe i ed defaults.
16.1.3 \Default" Constru tor
We have said that C++ supplies a onstru tor, if no onstru tor is given in the de nition of
a stru t. This onstru tor takes no arguments, and its body is empty. Su h onstru tor is
alled a default onstru tor, however the term is a tually used more generally: it has ome to
mean a onstru tor that an be alled with no arguments, even if su h a onstru tor has been
expli itly de ned by the programmer. Thus for V3 our onstru tor 2 is a default onstru tor.
Likewise, the bundled onstru tor de ned above would also be a default onstru tor.
A default onstru tor is needed if you wish to de ne arrays of a stru ture, be ause ea h
element of the array will be onstru ted only using the default onstru tor.
Note that C++ does not supply a default onstru tor if you give any onstru tor whatso-
ever. So if you de ne a non-default onstru tor (i.e. a onstru tor whi h must take at least
one argument), then the stru ture would not have a default onstru tor. Thus you would
not be able to reate arrays of that stru ture.
The default onstru tor is important also when we nest a stru ture inside another. We
dis uss this next.
16.1.4 Constru tors of nested stru tures
Suppose a stru ture X has other stru tures Y,Z,... as members. Then during the all to a
onstru tor for X, the onstru tors of Y,Z,... are alled before the body of the onstru tor
of X is exe uted. This happens re ursively, i.e. if Y in turn has members whi h are stru tures.
This rule sounds reasonable, but applying it an sometimes be tri ky. Consider the Point
and Cir le lasses as follows.
stru t Point{
double x,y;
Point(double p, double q){x=p; y=q;}
};
stru t Cir le{
Point enter;
double radius;
};
Consider what happens when we exe ute
Cir le ;
Abhiram Ranade, 2013. Do not distribute 286
As dis ussed above, the default onstru tor for Cir le will be alled. Sin e we did not supply
a onstru tor, C++ will reate one for us. Note however, that this onstru tor must rst
onstru t all the members of Cir le. To a omplish this, the onstru tor reated by C++
will all default onstru tors of all the members as well. So in our ase, the C++ onstru ted
onstru tor for Cir le will all the default onstru tor for Point. But the onstru tor of our
lass Point takes two arguments, and hen e is not a default onstru tor. Further, be ause a
onstru tor is given for Point C++ will not reate any onstru tors for Point. Thus writing
Cir le ; as above would be a ompiler error!
This problem an be solved using initialization lists.
16.1.5 Initialization lists
When a Point member is reated while onstru ting a Cir le obje t, we must somehow
indi ate that a two argument onstru tor must be used. We an do this if we write a
onstru tor for Cir le. Here is one possible way.
stru t Cir le{
Point enter;
double radius;
Cir le(double x, double y, double r) : enter(Point(x,y)), radius(r)
{
// empty body
}
};
The text following the : to the end of the line in the above ode is an initilization list.
The initialization list of a onstru tor says how the data members in the re eiver should be
onstru ted before the exe ution of the onstru tor itself an begin.
Thus in this ase the ode says that enter should be onstru ted using the onstru tor
all Point(x,y), where x,y are from the parameter list of the Cir le onstru tor. Similarly
the member radius of the Cir le being onstru ted is assigned the value r. In general, the
initialization list onsists of omma separated items of the form
member-name(initializing-value)
This will ause the member member-name to be initialized dire tly using initializing-value.
If the initializing value alls a onstru tor, then instead of writing out the all, just the
omma separated arguments ould be given. In our Cir le onstru tor, the initialization
list of enter happens by alling the onstru tor Point. Thus the initialization list an be
shortened as:
enter(x,y), radius(r)
Note that in our example, all the work got done in using the initialization lists, so the
body is empty. Note that we ould hoose to initialize only some of the members using the
initialization list and initialize the others in the body, if we wish. 1

1 Whenever possible you should perform initialization through initialization lists, be ause it is likely faster.
Abhiram Ranade, 2013. Do not distribute 287
16.1.6 Constant members
Sometimes we wish to reate stru tures in whi h the members are set at the time of the
initialization, but not hanged subsequently. This write-on e strategy of programming is
very omfortable: it is easier to reason about a program if you know that the values on e
given do not hange.
If we want our Point stru ture to have this property, then we would write it as follows.
stru t Point{
onst double x,y;
Point(double x1, double y1) : x(x1), y(y1)
{} // empty body
}
Noti e that we have given values to members x,y using initialization lists. Thus the members
will be assigned values when the stru ture is reated. Later on, the values annot be hanged;
indeed, the ompiler will ag an error if you write a statement su h as p.x = 5.0; where p
is of type Point.

16.2 The opy onstru tor


C++ allows you to spe ify how stru tures are passed to fun tions by value, and how they
an be returned from fun tions. The model for this is as follows. For every stru ture, C++
de nes by default a so alled opy- onstru tor. The opy onstru tor is used for opying the
value of a stru ture that is being passed to a fun tion as an argument, and also to opy ba k
the value if a fun tion returns a stru ture. A opy onstru tor takes a single argument, but
that argument has to be a referen e argument, otherwise we will need to (re ursively!) use
the opy onstru tor to opy that argument.
The default opy onstru tor merely opies ea h data member of the sour e stru ture to
orresponding member of the destination.
As you have probably guessed, you an yourself rede ne the opy onstru tor to do what
you wish. A onstru tor whi h takes a single parameter of type referen e to the stru ture
type, or onstant referen e to the stru ture type is onsidered to be a opy onstru tor. If
you de ne su h a onstru tor, that will be used for passing arguments by value and returning
values, instead of the automati ally generated opy onstru tor.
Below we show a opy onstru tor for our Queue stru ture.
stru t Queue{
int front, nWaiting, elements[QUEUESIZE℄;
Queue(){ // ordinary onstru tor;
front = nWaiting = 0;
}
Queue( onst Queue &other):
front(other.front), nWaiting(other.nWaiting){ // opy onstru tor
for(int i=front, j = 0; j<nWaiting; j++){
elements[i℄ = other.elements[i℄;
Abhiram Ranade, 2013. Do not distribute 288
i = (i + 1) % QUEUESIZE;
}
}
... members insert and remove...
};

As you an see the above implementation of the onstru tor does not opy the entire member
elements, but only the relevant portion of it. Clearly, this is more eÆ ient than opying the
entire stru ture.
The main use of the opy onstru tor will arise in onne tion with dynami memory
allo ation. We will see this in Se tion 19.3.2. Also see Se tion 16.11.1.

16.3 Destru tors


We know that a variable is destroyed when ontrol leaves the blo k in whi h the variable is
de ned. By default, destru tion of a variable simply means freeing the memory used for the
variable. However, we might wish to take other a tions besides freeing up the memory. For
this we may spe ify a destru tor member fun tion. If a variable of type T is being destroyed,
then the destru tor for T is alled on the variable, and only then the memory of the variable
is freed. The destru tor for stru t T is denoted as ~T, and is a spe ial member fun tion that
takes no arguments and has no return type. Here is an example.
stru t Queue{
... other member definitions as before ..
~Queue(){
if(nWaiting > 0)
out <<"Warning: Non-empty Queue being destroyed.\n";
}
};

int main(){
Queue q;
{
Queue q2;
q2.insert(5);
}
}
Anytime a Queue type variable is destroyed, the fun tion ~Queue will be automati ally alled.
This will print a warning if a queue ontaining elements is being destroyed { presumably
you might expe t that a queue should be destroyed only after all elements in it have been
pro essed.
In the above main program, when ontrol exits the inner blo k, the variable q2 will be
destroyed. This will ause the destru tor to be automati ally alled on q2. Sin e q2 will
not be then empty, the message will be printed. Just before the program terminates, the
Abhiram Ranade, 2013. Do not distribute 289
variable q will get destroyed. This will also ause the destru tor to be alled, on q. Sin e q
will then be empty, this will not ause a message to be printed.
Note that usually, it is an error to all the destru tor expli itly. It will be alled auto-
mati ally whenever a variable is to be destroyed. For now we know only one way a variable
an be destroyed: when ontrol leaves a blo k. In Se tion 19.1 we will see another way in
whi h variables an be destroyed, whi h will produ e alls to the destru tor.
In Se tion 19.3.1, the more ommon use of destru tors is des ribed. Also see Se -
tion 16.11.1.

16.4 Overloading operators


Consider the stru t V3 that we de ned in Se tion 15.3 for representing 3 dimensional ve tors.
In mathemati s, it is natural to add two ve tors, the result of whi h is a third ve tor, whose
omponents are the sums of the respe tive omponents of the rst two ve tors. To get the
sum of two ve tors, we de ned the member fun tion sum in Se tion 15.3. However, it might
be more natural to get the sum of ve tors by just using the addition operator. In other
words, suppose v,w are ve tors, i.e. variables of type V3. Wouldn't it be ni e if we ould
write v+w whi h would have the same e e t as sum(v,w)?
This is indeed possible. In this se tion we see how it an be done. For this we rst need
to understand how C++ interprets expressions involving operators su h as +.
If  is an in x operator, i.e. the operator is written between the operands as in
x  y
then C++ onsiders the above expression to be equivalent to
x . operator ( y )
This is merely a all to the member fun tion named operator, invoked on the obje t x,
with y as the argument. If su h a member fun tion is present, then the expression will be
a ordingly evaluated! Note that operator is a reserved word.
Here is how you ould de ne the operators + and * to work with our stru t V3.
stru t V3{
// members and onstru tors as defined earlier
V3 operator+ ( onst V3 &b) onst{
return V3(x + b.x, y+b.y, z+b.z);
}
V3 operator* (double t) onst{
return V3(x*t, y*t, z*t);
}
};
Be ause of the rst de nition, we an add two V3 obje ts to produ e a new V3 obje t,
identi al to what our member sum would have produ ed. The se ond de nition allows us to
multiply a V3 obje t by a double, exa tly mimi king the behaviour of the member fun tion
s ale. Thus, using these de nitions, we an write a mu h ni er looking main program:
Abhiram Ranade, 2013. Do not distribute 290
int main(){
V3 u,a;
double t;
in >> u.x >> u.y >> u.z >> a.x >> a.y >> a.z >> t;
out << u*t + a*t*t*0.5 << endl;
}
We note that this ability to de ne operator a tion for stru ture should be used with are.
Be ause of our familiarity of mathemati s, the interpretation of di erent operators is very
rmly xed in our minds. If we de ne operators re klessly, in onsistent with our intuition, it
is likely to produ e ode whi h will be onfusing. Indeed it is re ommended that arithmeti
operators be rede ned only for mathemati al quantities, where the operators are used in a
similar manner in mathemati s. Our de nition of + and * are onsistent with this be ause the
notion of adding mathemati al ve tors and multiplying a mathemati al ve tor by a number
are very standard.
When we de ne an operator a tion for a stru ture, we are said to be overloading the
operator. The following binary operators an be overloaded.
+ - * / % ^ & | < > == != <= >= << >> && ||
= += -= *= /= %= ^= &= |= <<= >>= [℄

We will see an example for the operator = in Se tion 16.6 and in Se tion 19.3.4, and for the
operator [℄ in Se tion 19.3.3.
In C++, fun tion alls an also be onsidered operators! Indeed, C++ treats a fun tion
all
f(a1,a2,...an)

as equivalent to
f . operator() (a1, a2, ..., an)

Thus, if f happens to be a stru t, for whi h the member fun tion operator() is de ned,
then it will get alled! In other words, you treat stru t instan es just like fun tions and
\ all" them if you wish. The stru t instan es whi h an be alled are often termed fun tion
obje ts. We will see an example of this in Se tion ??.
For overloading unary operators, see Appendix E.3.

16.5 Another overloading me hanism


We an overload an operator  also by de ning operator as an ordinary (non member)
fun tion on appropriate operand types. This is sometimes useful.
We will give two examples of this. We dis ussed above how you an de ne the multipli-
ation between a V3 obje t and a double. Suppose, for onvenien e we also wish to allow
the double to be spe i ed as the left hand operand, and the V3 obje t as the right hand
operand. In other words, we would like to be able to write 3*v as well as v*3. This an be
done by de ning the following (non-member) fun tion.
Abhiram Ranade, 2013. Do not distribute 291
V3 operator* (double fa tor, onst V3 & v){
return v*fa tor;
}
Here we are assuming that member fun tion operator* is already de ned in the lass V3.
For another example, suppose next that we wish to be able to print V3 obje ts on the
standard output stream just as we an print out the fundamental data types. This an be
done as follows.
ostream & operator<< (ostream & ost, V3 &v){
ost << v.x <<' '<< v.y <<' '<< v.z <<' ';
return ost;
}
This will de ne the operator << on left hand side operators of type ostream, whi h is indeed
the type of out, and right hand side operators of type V3.
As you an see, this fun tion will merely print out the x,y,z members separated by a
single spa e hara ter. The fun tion returns ost so that you an hain output operations,
i.e. so that you an write out << v1 << v2; (Se tion 12.6.3). Note that throughout we
are passing ostream obje ts by referen e, be ause ostream obje ts do not allow opying
(Se tion 16.7.2).
Not all operators an be overloaded as ordinary fun tions. In parti ular, the assignment
operator and various ompound assignment operators, the indexing operator [℄, the fun tion
all operator () and the arrow operator -> an only be overloaded using member fun tions.

16.6 Overloading assignment


The assignment operator is already de ned for stru tures: ea h member of the right hand
side stru ture is opied to the orresponding member of the left hand side stru ture. But
you an hange that if you wish.
Here is how you might override the default de nition of = for our stru ture Queue.
stru t Queue{
.. other members as before ..
Queue & operator=( onst Queue& rhs){
front = rhs.front;
nWaiting = rhs.nWaiting;

for(int i = front, j=0; j<nWaiting; j++){


elements[i℄ = rhs.elements[i℄;
i = (i + 1) % QUEUESIZE;
}
return *this;
}
};
Abhiram Ranade, 2013. Do not distribute 292
We do a member by member opy, ex ept that we dont opy the entire elements array but
just that part of it whi h is in use. Just as we did for the opy onstru tor of Queue. At
the end the fun tion returns a referen e to the urrent obje t on whi h the assignment is
invoked, i.e. the left hand side of the assignment as the value of the assignment expression
(Se tion 3.2.6). Thus we an write multiple assignments in the same statement if we wish,
i.e. of the form q1 = q2 = q3;.
Like the opy onstru tor, the main motivation for overloading assignment will be ome
lear when we onsider dynami memory allo ation, in Se tion 19.2.4.

16.7 A ess Control


Finally we onsider the last step in designing a produ t: pa kaging it so that only the ontrol
panel shows on the outside and the internal ir uitry is hidden.
C++ provides a simple way to hide members. The designer of a stru ture may designate
ea h member of the stru ture as either private, publi , or prote ted. Private members
an be a essed only inside the methods of the lass, and are not a essible outside the lass
de nition (but also see Se tion 16.7.3). Publi members, on the other hand, are onsidered
to be a essible by all. In other words, they an be used inside the lass de nition if needed,
but also outside of it. We will explain prote ted members later.
To spe ify a ess, we divide the members in the lass into groups, and before ea h group
pla e the labels publi :, private: or prote ted: as we want the members in the group
to be onsidered. You may use as many groups as you wish. For example we may de ne the
stru ture queue as:
stru t Queue{
private:
int front;
int nWaiting;
int elements[QUEUESIZE℄;
publi :
Queue(){...}
bool insert(int value){...}
int remove(){...}
};
In this, we have made the data members private, and the fun tion members publi . Thus, in
this ase if we wrote q.nWaiting = 7 outside the de nition, say in the main program, the
ompiler would ag it as an error. Be ause the onstru tor and the fun tions insert and
remove are publi , outside the de nition of Queue we an only use those.
Making the data members private is a very ommon idea. Typi ally, a arefully hosen
set of fun tion members is made publi .
16.7.1 A essor and mutator fun tions
Sometimes some data members are dire tly useful outside of an obje t. In su h ases, it is
onsidered appropriate to make them private, and allow a ess to them by de ning a essor
Abhiram Ranade, 2013. Do not distribute 293
and mutator fun tions.
stru t Point{
private:
double x, y;
publi :
double getx(){return x;} // a essor fun tion
void setx(double v){x = v;} // mutator fun tion
double gety(){return y;} // a essor fun tion
void sety(double v){y = v;} // mutator fun tion
}

With this de nition, we ould a ess and modify (or mutate) the oordinates of a point, even
though the orresponding data members are private.
Note however that the above strategy has an advantage as ompared to making the
members x,y publi . Suppose that tomorrow we de ide to represent a point using its polar
oordinates, say using members r and theta. Then we an still retain the member fun tions
de ned above, but only hange the bodies appropriately. For example, the fun tion getx
would now have to return r* os(theta). We would have to make hanges to the Point
de nition, however, we may not need to hange the ode that uses Point, sin e the user
ode does not dire tly a ess the data members.
16.7.2 Prohibiting ertain operations
Note that if we de ne a opy onstru tor or an assignment operator with either publi ,
private or prote ted a ess ontrol, C++ will not generate the default versions for these. If
we make any of these operators non-publi , then it will be equivalent to saying that they
annot be used at all outside the stru ture de nition. Thus if we make the assignment
operator private, then e e tively we are forbidding assignment for the stru ture. If we make
the opy onstru tor private, then we are e e tively saying that the stru ture annot be
passed by value, and also annot be returned.
In the ase of the lass Queue, there might be some reason to forbid the assignment as
well as passing by value. This is be ause intuitively we might think: an element an only
be in one queue, if we make a opy we are perhaps inviting errors. Note that even if we
make the opy onstru tor private, the obje t an still be passed to fun tions, but only by
referen e.
16.7.3 Friends
If you make some members of a stru t private, then they an only be a essed inside the
stru t de nition.
Sometimes this is too restri tive. For example, if you make data members private in stru t
V3, then using what you have seen so far, you will not be able to de ne the << operator as
we did in Se tion 16.5. This is be ause the fun tion operator<< in Se tion 16.5 refers to
the members x,y,z whi h we made private.
Abhiram Ranade, 2013. Do not distribute 294
C++ allows you to over ome this diÆ ulty. You go ahead and de ne the operator<<
fun tion as you wish, a essing the private members also. To enable the fun tion operator<<
to a ess the private members, you put a line de laring the fun tion as a friend in the
stru ture de nition.
stru t V3{
...
friend ostream & operator<< (ostream &ost, onst V3 &v);
...
}
This will de lare operator<< to be a friend, whi h means that it is allowed to a ess the
private members of V3. In general, the line will read friend fun tion-de laration.
Noti e that you ould have a heived the same e e t by de laring all members to be
publi . However, that would allow all fun tions a ess; by making a fun tion a friend, you
provide sele tive a ess.
The same fun tion an be a friend of several stru tures, and several fun tions be a friend
of the same stru ture. In fa t, you an have one stru ture A be a friend of another stru ture
B. This way, the private members of stru ture B an be used inside the de nition of stru ture
A. To do this you merely insert the line friend A; inside the de nition of stru ture B.

16.8 Classes
A stru ture as we have de ned it, ex ept for a minor di eren e, is more ommonly known in
C++ as a lass.
The small di eren e between the two is as follows. In a stru ture, all members are
onsidered publi by default, i.e. a member that is not in any group that is pre eded by
an a ess spe i er is onsidered publi . In a lass, all members are onsidered private by
default. To get the latter behaviour, you simply need to use the keyword lass instead of
stru t in the de nition.
lass Queue{
...
};
It is more ommon to use the term obje t to denote instan es of a lass.
In addition to the features onsidered in this hapter, there are a number of other features
in lasses/stru tures, the most notable of them being inheritan e, whi h we will onsider in
the following hapters.

16.9 Header and implementation les


Quite often, a lass (or stru t) will be developed independently of the program that uses it,
possibly by a di erent programmer. Thus we need a proto ol by whi h the ode that de nes
the lass an be a essed by ode in other les. Following our dis ussion of fun tions, it is
ustomary to organize ea h lass C into two les: C.h and C. pp.
Abhiram Ranade, 2013. Do not distribute 295
First, some important terms. It is ustomary to say that the body of ea h member-
fun tion provides an implementation of the member-fun tion. In fa t, the bodies of all
member fun tions together are said to onstitute an implementation of the lass itself. When
the implementation is given as a part of the lass de nition, it is said to be given in-line.
However, when lasses are large and developed independently, it is more ustomary to put
the de nition of a lass C without out the implementation, into the le C.h, the so alled
header le. The implementation is put into the le C. pp, using some spe ial syntax. If
there are any friend fun tions, their de larations an also put in C.h, and implementations
in C. pp. We show this using an example.
Consider the stru t V3 that we have been dis ussing all along. We will show example les
V3.h and V3. pp for it. We will make V3 be a lass, and de lare the data members x,y,z
as private, as is ustomary. The le V3.h ould be as follows.
lass V3{
private:
double x, y, z;
publi :
V3(double p=0, double q=0, double r=0);
V3 operator+(V3 onst &w) onst;
V3 operator*(double t) onst;
double length() onst;
friend ostream & operator<<(ostream & ost, V3 v);
};

ostream & operator<<(ostream & ost, V3 v);


We next show the implementation le V3. pp, whi h de nes the member fun tions. A
de nition of a member fun tion f appearing outside the de laration of a lass C is identi al
to the de nition had it appeared in-line, ex ept that the name of the fun tion is spe i ed as
C::f. The onstru tor for lass C will appear as C::C, of ourse.

#in lude <simple pp>


#in lude "V3.h"

V3::V3(double p, double q, double r){ // onstru tor


x = p; y = q; z = r;
}
// member fun tions
V3 V3::operator+(V3 onst &w) onst { return V3(x+w.x, y+w.y, z+w.z); }

V3 V3::operator*(double t) onst { return V3(x*t, y*t, z*t); }

double V3::length() onst { return sqrt(x*x+y*y+z*z); }

// other fun tions


ostream & operator<<(ostream & ost, V3 v){
Abhiram Ranade, 2013. Do not distribute 296
ost << "(" << v.x << ", "<< v.y << ", "<< v.z << ")";
return ost;
}
The last fun tion in the le is the friend fun tion operator<<.
It is a eptable if some of the implementations are pla ed in line in the header le.
Typi ally, small member fun tions are left in-line in the header le, while the large member
fun tions are moved to the implementation le.
If the lass ontains a stati data member, then the member is de lared (Se tion 15.6.1)
in the header le, and de ned in the implementation le.
16.9.1 Separate ompilation
We an now separately ompile the implementation le, and produ e, for the lass V3, the
obje t module V3.o. This module, and the header le, must be given to any programmer
who uses the lass V3. Suppose a program using V3 is ontained in the le user. pp, then
it must in lude the le V3.h. The program an now be ompiled by spe ifying
s++ user. pp V3.o
Other sour e/obje t les needed for the program must also be mentioned on the ommand
line, of ourse.
16.9.2 Remarks
The general ideas and motivations behind splitting a lass into a header le and an imple-
mentation le are as for fun tions. In whi hever le the lass is used, the header le must be
in luded, be ause the lass must be de ned. The implementation le or its obje t module
is needed for generating an exe utable.
If the header le hanges, but the publi part of the lass does not hange, the user
program needs to be re ompiled. If the publi part of the lass hanges, then likely the user
program will also have to hange to use the hanged lass de larations.

16.10 Template lasses


Like fun tions, we an templatize lasses as well. The pro ess of de ning a lass template is
very similar. Here is a template version of our V3 lass.
template<T>
lass V3{
private:
T x, y, z;
publi :
V3(T p=0, T q=0, T r=0){ x = p; y = q; z = r;}
V3 operator+(V3 w);
}
Abhiram Ranade, 2013. Do not distribute 297

template<T>
V3 V3::operator+(V3 w){ return V3(x+w.x, y+w.y, z+w.z); }
The template variable T determines the type of ea h omponent x,y,z, and is expe ted to
be spe i ed either as float or double. We have only shown 2 member fun tions for brevity.
One is de ned in-line, the other is de ned outside the lass de nition. Note that you must
put the line template<T> before the member fun tion de ned outside as well.
Note that the template de nition does not reate a lass, but a s heme to reate a lass.
To reate a lass, you must spe ify a value for the template variable and aÆx it in angle
bra kets to the lass-name. To reate a lass of the template with T being float, you simply
write:
V3<float> a,b, ;
This will reate the lass V3<float> from the template, as well as de ne a,b, to be variables
of type V3<float>. In your programs, you an use V3<float> as a lass name.
Note that the template for a lass must be present in every sour e le that needs to
use it. So it is ustomary to pla e it in an appropriate header le. Noti e that the lass is
generated only when an instan e is reated as in the line V3<float> a,b, ; above. Thus
there is no notion of separately ompiling a template.

16.11 Some lasses you have already used, almost


We should point out that you have already used lasses without knowing it.
16.11.1 Graphi s
By now you have probably realized that our graphi s ommands (Chapter 5 and elsewhere)
are built using lasses. Indeed, the names Turtle, Re tangle, Polygon, Line, Point are
all names of lasses. The ommands to reate reate orresponding obje ts on the anvas
were merely orresponding onstru tors. The various operations we have des ribed on the
graphi s obje ts are member fun tions.
You an perhaps guess how the ability to write our own onstru tors et . helps in devel-
oping a graphi s library. When we exe ute a statement su h as
Turtle t;

not only must we reate a variable, but we must also draw the turtle on the s reen. This
drawing operation an be done inside the Turtle onstru tor! Similarly, when a graphi s
obje t is destroyed, the s reen must be redrawn to remove that obje t from view. This is
done as a part of the destru tor! In general, there are a number of book-keeping operations
needed when dealing with graphi s obje ts, the ode for these an be onveniently pla ed in
the onstru tors, destru tors, and other appropriate member fun tions.
Abhiram Ranade, 2013. Do not distribute 298
16.11.2 Standard input and output
Yes, in and out are obje ts, respe tively of lass istream and ostream. But you an have
other obje ts of these lasses too, as we see next.
16.11.3 File I/O
You an use les for I/O, i.e. input and output in your programs. For reading les you rst
need to insert the line
#in lude <fstream>

at the beginning of the le, along with other lines you may have su h as #in lude <simple pp>.
On e you have this you an reate a so- alled input stream, by writing:
ifstream myinfile("input.txt");
This reates a variable alled myinfile in your program, of lass ifstream, whi h is a
sub lass of istream. The quoted name inside the parentheses tells where the stream will get
its data: in this ase, the statement says that the values will ome from the le input.txt
whi h must be present in the urrent working dire tory. After this, you an treat the name
myinfile just as you treat in, and you an write statements su h as myinfile >> n; whi h
will ause a whitespa e delimited value to be read from the le asso iated with myin le into
the variable n.
Note that just as you an write assert( in) to he k whether there was an error in
reading or if the stream has ended, so an you write assert(myinfile). In both ases, if
there is an error or if the stream ends, the variable will be ome NULL and hen e the assertion
will fail.
In a similar manner you an write
ofstream myoutstream("output.txt");

whi h will reate the variable myoutstream, of lass ofstream, sub lass of ostream, and
asso iated with the le output.txt. You an treat myoutstream just like out, i.e. you an
write values to it using statements su h as myoutstream << n;. The values will get written
to the asso iated le, in this ase output.txt, whi h will get reated in the urrent working
dire ory.
Here is a program whi h takes the rst 10 values from a le squares.txt whi h is
expe ted to be present in your urrent dire tory, and opies them to a le square opy.txt,
whi h will get reated.
#in lude <simple pp>
#in lude <fstream>

main_program{
ifstream infile("squares.txt");
ofstream outfile("square opy.txt");
Abhiram Ranade, 2013. Do not distribute 299
int val;
repeat(10){
infile >> val;
outfile << val << endl;
out << val << endl;
}
}
The values are also printed out on out whi h means they will also appear on the s reen
(unless you redire t standard out during exe ution). Noti e that we have hosen to enter an
end of line after ea h value, while printing to outfile as well as out.

16.12 Remarks
This hapter provides you with the tools to develop well pa kaged data stru tures. You will
typi ally make the data members private; and make a subset of member fun tions publi .
Of ourse, pa kaging requires some amount of areful programming e ort. Hen e, how mu h
pa kaging to put is your hoi e, to be determined by how you expe t your ode to be used
by others. If your ode is meant for your own, one time use, perhaps it suÆ es to have no
pa kaging: use a stru t rather than a lass and keep everything visible. However, good
programs tend to evolve. If your program works well, you will inevitably want to make it do
more things. So in general, it is a good idea to pa kage your data stru tures well from the
very beginning. It will save e ort in the long run.

16.13 Exer ises


1. De ne a lass for storing polynomials. Assume that all your polynomials will have
degree at most 100. Write a member fun tion value whi h takes a polynomial and
a real number as arguments and evaluates the polynomial at the given real number.
Overload the +,*,- operators so that they return the sum, produ t and di eren e of
polynomials. Also de ne a member fun tion read whi h reads in a polynomial from
the keyboard. It should ask for the degree d of the polynomial, he k that d  100,
and then pro eed to read in the rst d + 1 oeÆ ients from the keyboard. De ne a
print member fun tion whi h auses the polynomial to be printed. Make sure that you
only print d + 1 oeÆ ients if the a tual degree is d. Carefully de ide whi h members
will be private and whi h will be publi . Overload the >>, << operators so that the
polynomial an be read or printed using them.
2. De ne a lass for storing omplex numbers. Provide 0, 1, 2 argument onstru tors
whi h respe tively onstru t the omplex number 0, a omplex number with imaginary
part 0 and real part as spe i ed by the argument, and a omplex number with real
and imaginary parts as spe i ed by the arguments. Overload the arithmeti operators
to implement omplex arithmeti .
3. Sometimes we dont know the exa t values of ertain quantities, but only know that
the value lies in an interval, say between some numbers L and H . In su h ases, we
Abhiram Ranade, 2013. Do not distribute 300
might hoose to represent the quantity by the pair of numbers L; H . In other words,
we are representing ea h quantity by the interval [L; H ℄. If you have two quantities
represented by intervals [L ; H ℄ and [L ; H ℄, then learly their sum must lie in the
1 1 2 2
interval [L + L ; H + H ℄. Thus the last interval ould be onsidered to be the sum of
1 2 1 2
the rst two intervals. Su h a representation is quite useful when there is un ertainty
in our knowledge of a quantity.
De ne a lass Interval whi h enables us to represent quantities whi h we know lie
in a ertain interval. Overload the arithmeti operators so that you an perform
arithmeti on these quantities while keeping tra k of the un ertainty. Be areful:
although in general the un ertainty in reases when you perform arithmeti , if you
subtra t a quantity (however un ertain) from itself, you get 0 with ertainty. Your
implementation should deal with su h possibilities properly. For this, you will have to
de ide whether two referen es R1,R2 are in fa t identi al. You an do this by writing
&R1 == &R2.

4. Modify the Queue lass so that it is not possible to make a opy of a Queue obje t,
or assign to it. Then write a main program that attempts to make a opy or an
assignment. Observe that the ompiler will tell you that you are trying to perform an
operation that is disallowed.
5. The Queue lass as de ned in the hapter is to be used for storing integers. But you
may want to queues in whi h to store double quantities, or in general obje ts of any
(single) lass. Templatize the Queue lass so that this an be done.
6. De ne a Car lass for showing a ar on the s reen. A ar should have a polygonal
body, and two ir ular wheels. Add spokes to the wheels. It should be possible to
onstru t ars and move them. When a ar moves, the wheels should rotate. Add
member fun tions to s ale the ar as well.
7. Constru t a lass Button whi h an be used to reate an on-s reen button, say a
re tangle, whi h an be li ked. Clearly, you should be able to onstru t buttons at
whatever positions on the s reen, with whatever text on them. Also, buttons should
have a member fun tion li kedP whi h takes an int denoting the position of a li k,
as obtained from getCli k(), and determines whether the li k position is inside the
button. What other member fun tions might be useful for buttons?
Chapter 17

A proje t: osmologi al simulation

It ould perhaps be said that the ultimate goal of S ien e is to predi t the future. S ientists
seek to dis over s ienti laws so that given omplete knowledge of the world at this instant,
the laws will enable you to say what ea h obje t will do in the next instant. And the next
instant after that. And so on. Predi ting what will happen to the entire world is still very
diÆ ult, partly be ause we do not yet know all laws governing all obje ts in the world. Even
if we knew all the laws, predi ting what happens to a large system is diÆ ult be ause of
the enormous number of omputations involved. However, for many systems of interest,
we an very well predi t how they will behave in di erent ir umstan es. For example, we
understand the physi s of ollisions and of the materials used in a ar well enough to predi t
how badly a ar will be damaged if it ollides against a barrier of ertain strength at a ertain
velo ity. The term simulation is often used to denote this kind predi tive a tivity. Indeed
many produ ts are built today only after their designs are simulated on a omputer to see
how they hold up under in di erent onditions.
In this hapter and Chapters 25 and 26, we will build a number of simulations. The
simulation in this hapter is osmologi al. Suppose we know the state of the stars in a
galaxy at this instant. Can we say where they will be after a million years? Astronomers
routinely do simulations to answer su h questions. We will examine one natural idea for doing
su h simulations, and then examine the aws in that idea. We will then see an improved
idea, whi h will still be quite naive as ompared to the ideas used in professional programs.
We will ode up this idea. We wil use our graphi s ma hinery to show the simulation on the
s reen.

17.1 Mathemati s of Cosmologi al simulation


In some sense, simulating a galaxy is rather simple. For the most part, heavenly bodies
intera t with ea h other using just Newton's laws of motion and gravitation. As you might
1

re all, the law of gravitation states that, two masses ma ; mb with separated by a distan e d
attra t ea h other with a for e of magnitude
Gma mb
d2
1 We will sti k to the non-relativisti laws for simpli ity.
301
Abhiram Ranade, 2013. Do not distribute 302
where G is the gravitational onstant. The ve tor form of this is also important. If ra ; rb
are the ve tors denoting the positions of the masses, then the distan e between the masses
is d = jrb ra j. The for e on mass ma is in the dire tion rb ra, and hen e we may write
the for e on mass ma in ve tor form as
Gma mb (rb ra )
jrb raj
3
(17.1)
If planets ollide, then presumably more omplex laws have to be brought in, whi h might
have to deal with how their hemi al onstituents rea t. But a substantial part of the simu-
lation only on erns how the heavenly bodies move under the e e t of the gravitational for e.
It is worth noting that su h simulations have ontributed a great deal to our understanding
of how the universe might have been reated and in general about osmologi al phenomenon.
Also, the ideas used in the simulations are very general, and will apply in simulating other
(more earthly!) physi al phenomenon involving uid ow, stresses and strains, ir uits and
so on.
Our system, then, onsists of a set of heavenly bodies, whi h we will refer to as stars
for simpli ity. The state of the system will simply onsist of the position and the velo ity
(magnitude and dire tion) of the stars. Suppose we know the initial state, i.e. for ea h star
i we know its initial position ri and velo ity vi (both ve tors). Suppose we want to know
the values after some time . Letting ri0 ; vi0 be the values after time , we may write:
ri0 = ri + vi  
vi0 = vi + ai  
where vi is the average velo ity (ve tor) of the ith parti le during the interval [t ; t + ℄
0 0
and ai is the average a eleration during the interval. We do not know the average velo ities
and a elerations, and indeed, it is not easy to ompute these quantities. However, the key
observation, attributed to Euler, is that if the interval size  is small, then we may assume
with little error that the average velo ity remains un hanged during the interval for the
purpose of al ulating the position at the end of the interval. Euler's observation is similar
to the idea we used in Se tion 8.2 to integrate f (x) = 1=x; the value of f was not really
onstant during every interval, but we assumed it is onstant provided the interval is small
enough. Assuming that the average velo ity is simply the velo ity at the beginning we may
write
ri0 = ri + vi  (17.2)
Now, we an easily al ulate the new position ri0 for ea h parti le, be ause we know ri; vi.
Euler's observation also applies to the a eleration: if the interval is small, then the a eler-
ation does not hange mu h during it. Thus the average a eleration an be assumed to be
the a eleration at the beginning, and we may write:
vi0 = vi + ai  (17.3)
We are not given ai expli itly, but we have all the data to al ulate it. The a eleration of
the i th star is simply the net for e on it divided by its mass mi. The net for e is obtained
Abhiram Ranade, 2013. Do not distribute 303
by adding up the gravitational for e on star i due to all other stars j 6= i. But we know how
to al ulate the for e exerted by one star on another. Thus we may write:
F X Gmj (rj ri )
ai = i = (17.4)
mi j 6 i jrj ri j
=
3

We have des ribed above a pro edure by whi h we an get the state of all parti les at
time t + given their state at time t. Our answers are approximate, but the approximation
is likely to be good if  is small. Pi king a good  is tri ky; we will assume that we are
somehow given a value for it. Suppose now that we know the state of our system at time
t = 0, and we want the state at time t = T . To do this, we merely run T= steps of our
basi pro edure! In parti ular, we use our basi pro edure to al ulate the state at time 
given the state at time 0. Then we use the state omputed for time  as the input to our
basi pro edure to get the state for time 2, and so on. This may be written as:
1. Read in the state at time 0, i.e. the values ri; vi; mi for all i.
2. Read in ; T .
3. For step s = 1 to T=:
(a) Cal ulate ri0 a ording to equation (17.2) for all i.
(b) Cal ulate ai a ording to equation (17.4) for all i.
( ) Cal ulate vi0 a ording to equation (17.3), for all i.
(d) Set ri = ri0 , vi = vi0 for all i
4. end for
5. Print ri; vi for all i.
We will not present the ode for this algorithm, but you should be able to write it quite
easily.
It turns out that this method an be extremely slow, be ause the stepsize  must be
taken very small to ensure that the errors are small. However, there are many variations on
the method whi h have better running time and high a ura y. One su h variation employs
the following rule to ompute ri0
ri0 = ri + vi  + ai  =2
2
(17.5)
where ai is to be al ulated as before. You may re ognize this form. Perhaps you have studied
a formula in kinemati s for the ase of uniform a eleration of a parti le: s = ut + at =2,2

in whi h s is the distan e overed, u the initial velo ity, a the a eleration, and t the time.
Our formula is really the same, with the a eleration, initial velo ity and time being ai; vi; 
respe tively.
The rule to ompute vi0 an also be re ned as follows.
a + a0
vi0 = vi + i i  (17.6)
2
Abhiram Ranade, 2013. Do not distribute 304
1. Read in the state at time 0, i.e. the values ri; vi; mi for all i.
2. Read in ; T .
3. For step s = 1 to T=:
(a) Cal ulate ai using equation (17.4) for all i.
(b) Cal ulate ri0 using equation (17.5) for all i. Update ri = ri0 for all i.
( ) Cal ulate a0i using equation (17.4) for all i.
(d) Cal ulate vi0 using equation (17.6) for all i. Update vi = vi0 , for all i.
4. end for
5. Print ri; vi for all i.
Figure 17.1: Basi Leapfrog
in whi h a0i is the a eleration al ulated at the new positions of the stars, i.e. using equa-
tion 17.4 but with ri0 instead of ri. It is not hard to understand the intuition behind this
formula. The a eleration at the beginning of the interval is ai, and at the end is a0i. The
ai a0i
average of these, , is likely to be a better estimate of the a eleration during the interval
+

rather than simply ai . This is what the above rule uses. Equations 17.5 and 17.6 are said to
2

onstitute the Leapfrog method of al ulating the new state. The algorithm in Figure 17.1
is based on this.
You will note that the algorithm in Figure 17.1 is ineÆ ient: the value a0i al ulated at
the end of an iteration of the loop is re al ulated at the beginning of the next iteration. We
will avoid this in the ode we des ribe later.
It turns out that the Leapfrog method does indeed give more a urate results for the
same value of  as ompared to the simpler rules in Equations (17.2,17.3). Of ourse, the
story does not end here. State of the art programs for harting the evolution of stars use
even more re ned methods. These are outside the s ope of this book.

17.2 Overview of the program


Let us rst learly write down the spe i ations. Our input will be positions and velo ities
of a ertain set of stars at time 0. We will also be given a number T . Our goal will be to nd
the positions and velo ities of the stars at time T . We are also asked to show the traje tories
tra ed by the stars between time 0 and time T .
The rst question in writing the program is of ourse how to represent the di erent
entities in the program. The main entity in the program is a star, of ourse. A star has
several attributes, its velo ity and position, and its mass. The mass is simply a oating point
number. However, the velo ity and position both have 3 omponents, orresponding to ea h
spatial dimension. Clearly, we an use our V3 lass of Se tion 16.9 to represent positions,
velo ities, and a elerations. The traje tory of a star is also to be shown on the s reen.
Abhiram Ranade, 2013. Do not distribute 305
1. Read in the state at time 0, i.e. the values ri; vi; mi for all i.
2. Read in ; T .
3. Cal ulate ai using equation (17.4) for all i.
4. Cal ulate ri0 using equation (17.5) for all i. Update ri = ri0 for all i.
5. For step s = 2 to T=:
(a) Cal ulate a0i using equation (17.4) for all i.
(b) Cal ulate vi0 using equation (17.6). Update vi = vi0 , for all i.
( ) Update ai = a0i for all i.
(d) Cal ulate ri0 using equation (17.5) for all i. Update ri = ri0 for all i.
6. end for
7. Print ri; vi for all i.
Figure 17.2: Final Leapfrog algorithm
So we probably should asso iate a graphi s obje t, say a Point, with ea h star. When we
ompute the new position of a star, we should move the Point asso iated with the star. The
star lass will need a onstru tor and some methods to implement the position and velo ity
updates as per Equations (17.5,17.6).
As we mentioned in the previous se tion, the value a0i al ulated at the end of the sth
iteration is the same as the value ai al ulated at the beginning of the s + 1th iteration.
However, when s = 1, we do need to al ulate ai be ause there is no previous iteration. So
we rearrange the ode slightly, as shown in Figure 17.2.
Figure 17.2 is really a slight rearrangement of the ode in Figure 17.1, in the manner
of Figure 7.2. We pulled up statements 3(a), 3(b) out of the loop of Figure 17.1, and they
be ome statements 3, 4 in Figure 17.2, and they also get added to the end of the loop, i.e.
be ome statements 5( ), 5(d). Note that ai of the next iteration is the a0i of the previous, so
in statement 5( ) we did not re al ulate ai, but merely set ai = a0i . Note that the new loop
is run 1 step less be ause we e e tively pulled out one step out.
17.2.1 Main Program
The main program will reate the stars. It will maintain a variable to keep tra k of the
elapsed time. It will advan e this variable in small steps to rea h the given duration T . As
it advan es time, it will al ulate the for es, and all appropriate methods on the stars to
update their positions and velo ities.

int main(int arg , har* argv[℄){


initCanvas("Star satellite system",800,800);
Abhiram Ranade, 2013. Do not distribute 306
ifstream simDatafile(argv[1℄);
int n; simDatafile >> n;
Star stars[n℄;
onst float star_radius_for_graphi s = 15;

float T, delta; simDatafile >> T >> delta;


setup_star_data(simDatafile, stars, n, star_radius_for_graphi s);

arstep(n,stars, delta);

for(float t=0; t<T; t+=delta){


avrstep(n,stars, delta);
}
wait(5);
}
The program reates the anvas to show the orbits, then opens the le ontaining the data
about the simulation. It expe ts the lename to be spe i ed as a ommand line argument.
From the spe i ed le, it reads n, the number of stars, T, the time duration of the simulation,
and delta the time step duration, i.e. the value . Next, the fun tion setup star data
reads the data about the stars into the array stars of lass Star. It pla es the data read
into ea h star obje t.
void setup_star_data(ifstream & file, Star stars[℄, int n, float radius){
float mass, x, y, z, vx, vy, vz;
for(int i=0; i<n; i++){
file >> mass >> x >> y >> z >> vx >> vy >> vz;
stars[i℄.init(mass, V3(x,y,z), V3(vx,vy,vz), radius);
}
assert(file); // qui k he k that input was valid
}
Next the program alls the fun tion arstep orresponding to steps 3,4 of Figure 17.2. Then,
within the loop, the fun tion avrstep is alled, orresponding to steps 5(a){5(d). The
fun tion arstep is as follows.
void arstep(int n, Star stars[℄, float delta){
V3 for es[n℄;
al ulate_net_for e(n, stars, for es);
for(int i=0; i<n; i++)
stars[i℄.arStep(delta, for es[i℄);
}
As you an see, it al ulates the for es on ea h star due to other stars, using the fun tion
al ulate net for e. The for e on ea h star is passed as an argument to the arstep
method of ea h star. The avrstep fun tion is identi al, ex ept that it alls the avrstep
method for ea h star.
The task of al ulating for es is fairly simple as you would expe t.
Abhiram Ranade, 2013. Do not distribute 307
void al ulate_net_for e(int n, Star stars[℄, V3 for es[℄){
for(int i=0; i<n; i++) for es[i℄=V3(0,0);

for(int i=0; i<n-1; i++){


for(int j=i+1; j<n; j++){
V3 distve = stars[j℄.getr() - stars[i℄.getr();
double dist = distve .length();
double fmag = stars[i℄.getMass()*stars[j℄.getMass()/(dist*dist);

V3 f(distve *(fmag/dist)); // for e on star i


for es[i℄ = for es[i℄ + f;
for es[j℄ = for es[j℄ - f;
}
}
}
Sin e the for e due to star i on star j has the same magnitude as the for e due to star j on
star i, but opposite dire tion. So we al ulate the for e just on e, and add it to the total
for e on star i, and subtra t it from the total for e on star j . Noti e how the V3 lass makes
it easy to write this fun tion.
These fun tions an be pla ed in a le, main. pp.

17.3 The lass Star


The header le star.h is as follows.
lass Star {
private:
Cir le image;
float mass;
V3 r,v,a; // position, velo ity and previous a eleration values.
publi :
Star(){};
V3 getr(){return r;}
void init(float m, V3 position, V3 velo ity, float radius);
void arStep(float dT, V3 f);
void avrStep(float dT, V3 f);
float getMass(){ return mass;}
};
The data member image, of lass Point, will be used for produ ing the graphi al animation.
The x,y oordinates of the position (stored in member r) will be used as the position of
ea h body on the s reen; you may onsider that we are viewing the osmologi al system in
the z dire tion, so that only the x,y oordinates are important. The member image will be
made to put down its pen, so that the orbit will be tra ed on the s reen, as you will see in
the member fun tion init, in the implementation le star. pp below.
Abhiram Ranade, 2013. Do not distribute 308
#in lude "V3.h"
#in lude "star.h"
void Star::init(float m, V3 r1, V3 v1, float radius){
mass = m;
r = r1;
v=v1;
image.init(radius,Position(0,0),Position(r.getx(),r.gety()));
image.setFillColor(COLOR("red"));
image.setFill(true);
image.show();
image.penDown();
}

void Star::arStep(float dT, V3 f){ // first step, outside loop


a = f*(1/mass);
V3 d = v*dT + a*dT*(dT/2);
image.move(d.getx(),d.gety()); // update anvas
r = r + d;
}

void Star::avrStep(float dT, V3 f){ // basi loop step


V3 adash = f*(1/mass);
v = v+(a+adash)*(dT/2);
a = adash;
V3 d = v*dT + a*dT*(dT/2);
image.move(d.getx(),d.gety()); // update anvas
r = r + d;
}

It should be self explanatory.

17.4 Compiling and exe ution


The les an be ompiled by giving
s++ main. pp star. pp V3.o
where we assume that V3.h and V3.o from Se tion 16.9 are in the same dire tory as main. pp
and star. pp.
To exe ute the program we need a le ontaining the data for stars. A sample le
3stars.txt is as follows.

3
3000
10
100 497.00436 375.691247 0 0.466203685 0.43236573 0
Abhiram Ranade, 2013. Do not distribute 309

Figure 17.3: 3 stars in a gure of 8 orbit


100 400 400 0 -0.932407370 -0.86473146 0
100 302.99564 424.308753 0 0.466203685 0.43236573 0
This is meant to simulate a 3 star system for 1000 steps, with  = 10. The initial positions
and velo ities of the stars are given as above. Note that they have been arefully al ulated.
You an simulate this system by typing:
./a.out 3stars.txt
The stars will tra e an interesting gure of 8 orbit on whi h they will hase ea h other.
Figure 17.3 gives a snapshot. The stars have their pen down, and hen e the orbits tra ed
are also visible.

17.5 Con luding Remarks


There are a number of noteworthy ideas presented in this hapter.
The general notion of simulating systems of interest is very important. Given the initial
state of a system, and the governing laws, we an in prin iple determine the next states.
However, as we saw, the governing laws an be applied in more or less sophisti ated ways,
leading to more or less error in the result. Texts on numeri al analysis will indi ate how
the error an be estimated, and will also give even more sophisti ated ideas than what we
presented.
Our program also illustrates two important program design ideas. First is the idea of
building lasses to represent the entities important in the program. Clearly, the important
entities in our program were the stars: so we built a lass to represent them. But as we
noted, there were many ve tor like entities in the problem: so it was useful to build the
lass V3 as well. Finally, note that we did not write one long main program: we identi ed
important steps in the main program and used fun tions to implement those steps. The
fun tions, even if used just on e, more learly indi ated the omputational stru ture of our
algorithm.
Finally, a small te hni al point should also be noted. We needed to reate an array of
Star obje ts. As we indi ated in Se tion 16.1.3, when an array of obje ts is reated, ea h
obje t an be initialised only using the onstru tor whi h takes no arguments. Hen e we
had a Star() onstru tor. But this leaves open the question of how to pla e data in ea h
obje t. For this, a ommon idiom is to provide an init member fun tion, as we did. We
all the init fun tion on ea h obje t in the array and set its ontents. This idiom will ome
in useful whenever you need arrays of obje ts in your programs.
Abhiram Ranade, 2013. Do not distribute 310
17.6 Exer ises
1. Run the osmologi al simulation given in the text. Use it to simulate a system onsist-
ing of a planet orbiting a star. Modify the given ode so that it uses the rst (simpler)
method dis ussed in the hapter. Compare the two methods. For small enough ve-
lo ities, the planet will travel around the star for both methods. You will observe,
however, that for Euler's method, the orbit will keep diverging for any stepsize, whi h
is learly erroneous. For the same stepsize, you should be able to observe that the
leapfrog orbit does not diverge, or diverges mu h less.
2. Consider an elasti string of length L tied at both ends. Suppose it onsists of n
equal weights, onne ted together by springs of length L=n + 1. Suppose ea h spring
has Hooke's onstant k, i.e. if the string is stret hed by distan e x, a tension kx is
produ ed. Suppose one of the masses is moved to some new position. Suppose the
string is at rest after this. Clearly, the springs on either side of the mass will stret h
equally, if gravity is ignored. Now suppose the mass is released. Simulate the motion
assuming there is no gravity.
3. Consider a sequen e of ars travelling down a single lane road. In a simplisti model,
suppose that the ars have the same maximum speed V , and a eleration a and de-
eleration d. Suppose ea h ar attempts to ensure that it an ome to a halt even if
the ar ahead of it were to stop instantaneously (e.g. be ause of an a ident). Further
assume that the driver is aware of this distan e, and slows down if the distan e ahead
redu es, and speeds up if the distan e in reases, but only till the speed rea hes V .
Build a simulation of a onvoy of ars whi h travels along the road on whi h there are
signals present. When a signal turns red, the leading ar in the onvoy brakes so that it
omes to a halt at the signal. Of ourse, the drivers do not rea t immediately, but have
some response time. Note though that usually it is very easy to see if the ar ahead is
slowing down, be ause the tail red light omes on. In orporate su h details into your
simulation. Show an animation of the simulation using our graphi s ommands.
Chapter 18

Graphi s Events

You already know that the fun tion getCli k auses the program to wait for the user to
li k on the graphi s anvas, and then returns a representation of the oordinates of the li k
position. However, it is possible to intera t in a ri her manner with the graphi s anvas. It
is possible for your program to wait for the mouse to be dragged, or a key to be pressed, or
a similar su h event. After the event happens, you an de ide what a tion to take. Using
the features that we will dis uss in this hapter, you should be able to write very intera tive
and easy to use programs, and even games.
We begin by des ribing how you an wait for events, and nd out exa tly what event has
happened. After that we will sket h two appli ations.

18.1 Events
By event we will mean one of the following:
1. A button on the mouse being pressed.
2. A button on the mouse being released. It must have been pressed earlier.
3. The mouse being dragged. By this is meant the movement of the mouse with some
button pressed.
4. A key being pressed on the keyboard.
If the user performs any of these a tions with the graphi s anvas a tive (often alled \having
fo us"), then it is onsidered to be an event. Note that the graphi s anvas be omes a tive
if you move the mouse over it and press any of the mouse keys, and remains a tive so long
as you keep the mouse within the anvas.
18.1.1 Event obje ts
Obje ts of lass XEvent are used to hold information about events. They are passed (by
referen e) to fun tions that pla e information in them about events that have happened, or
to fun tions that extra t information pla ed in them earlier.
We will not des ribe the lass XEvent fully, but will dis uss only the relevant details
below as needed.
311
Abhiram Ranade, 2013. Do not distribute 312
18.1.2 Waiting for events
The fun tion nextEvent has the signature:
void nextEvent(XEvent &event);
A nextEvent all auses the program to wait for an event to happen. In this it is like
the statement in >> ..., whereupon the program waits for input to be given. When the
fun tion returns, the argument event will ontain information about the event that has
taken pla e. The program an extra t this information and a ordingly take a tions.

18.2 Che king for events


The fun tion he kEvent has the signature
bool he kEvent(XEvent &event);
A all to he kEvent returns true if an event has happened sin e the last all to nextEvent
or he kEvent. It If no event has taken pla e sin e the last all to nextEvent or he kEvent
then the fun tion just returns false.
It is worth emphasizing that the he kEvent fun tion does not wait, unlike nextEvent.
18.2.1 Mouse button press events
The fun tion mouseButtonPressEvent when alled on an event returns true i the event is
of type mouse button press. On e you know that the event is of type mouse button press,
you an get additional information about it using the members event.xbutton.button,
whi h returns an integer denoting whi h button was pressed, and event.xbutton.x and
event.xbutton.y whi h give the oordinates of the mouse at the time the button was
pressed. Here is an example.
XEvent event;
nextEvent(event);
if(mouseButtonPressEvent(event)){
out <<"Mouse button "<< event.xbutton.button
<<" pressed, at position ("<< event.xbutton.x <<
<<", "<< event.xbutton.y << endl;
}
This ode will ause the program to wait until some event happens, and then if the event
was the pressing of some mouse button, it will print whi h button was pressed (i.e. 1, 2 or
3) and at what anvas oordinates.
18.2.2 Mouse drag events
The fun tion mouseDragEvent when alled on an event returns true i the event was a
mouse drag, i.e. the user dragged the mouse after pressing a mouse button. The members
event.xmotion.x and event.xmotion.y give the oordinates of the drag position.
Abhiram Ranade, 2013. Do not distribute 313
18.2.3 Key press events
The fun tion keyPressEvent when alled on an event returns true i the event was the
pressing of a key of the keyboard. The fun tion harFromEvent applied to the event returns
the har denoting the key that was pressed. The members event.xkey.x and event.xkey.y
respe tively give the oordinates of the position at whi h the key was pressed.

18.3 A drawing program


Here is a simple program whi h enables you to draw on the anvas.
int main(){
initCanvas("Draw using the mouse", 800,500);
onst har es apekey = '\33';
XEvent event;
short lastx=0, lasty=0;
while(1){
nextEvent(event);
if(mouseButtonPressEvent(event)){
lastx = event.xmotion.x; lasty = event.xmotion.y;
}
if(mouseDragEvent(event)){
imprintLine(lastx, lasty, event.xbutton.x, event.xbutton.y);
lastx = event.xbutton.x; lasty = event.xbutton.y;
}
if(keyPressEvent(event)){
if( harFromEvent(event) == es apekey) break;
}
}
}
In this we have used the imprintLine fun tion rather than reate a line and alling imprint
on it. In our experien e, the latter is too slow { the line drawing lags behind the ursor
movement.

18.4 A rudimentary Snake game


Perhaps many of you are familiar with a game alled Snake, variations of whi h are available
on many omputers and even mobile phones.
The essen e of the game is to ontrol a snake that keeps on moving on the s reen. The
player may have goals su h as steering the snake towards food/prizes, or preventing it from
hitting obsta les. There may be variations in whi h the tail of the snake might grow as it eats
food. Typi ally the snake is represented as a sequen e of segments (vertebrae!). The head,
or segment 0 has a movement dire tion, North, East, South or West, and it keeps moving
one step in that dire tion per time step. The subsequent segments follow, i.e. segment i
Abhiram Ranade, 2013. Do not distribute 314
moves to the position of segment i 1, for i  1. The player an hange the dire tion of the
head movement to a new dire tion, say by typing in n,e,s,w.
Here we will develop the ore logi e of the game, i.e. show the snake on the s reen and
enable the player to hange its dire tion. The addition of prizes et . are left for the exer ises.
18.4.1 Spe i ation
We have more or less des ribed the spe i ations above. Perhaps only one lari ation
is needed: the segments of the snake will move on a two dimensional grid, with the grid
separation being gridsep.
18.4.2 Classes
As we have mentioned, we should have a lass for all the important entities ontained in our
program. So learly we must have a Snake lass.
The snake will have a body whi h onsists of several segments. So it is natural to
onsider an array named body onsisting of Cir les, where we have arbitrarily de ided that
the segments be ir ular. We will use a onstant length to denote the number of segments
in the body. Ea h segment will maintain its own position, so we need not have an additional
position attribute for the snake. However, it is useful to keep data member giving the urrent
dire tion of movement. Sin e the movement is only along the four dire tions, we have hosen
type har for this member, and it is expe ted to take values 'n', 'e', 's', 'w'.
When the snake moves, segments 1 through length-1 move into the positions of the
segments 0 through length-2. So in e e t, be ause the segments are visually identi al,
it might seem that the segments 1 through length-2 stay xed, while segment length-1
moves to the position where segment 0 is expe ted to move. Our ode in fa t does this.
Note that this means that what was previously segment i be omes segment i-1 % length.
So instead of opying around the segments within the array body, we merely keep an data
member headindex whi h gives the index of the segment whi h is the head of the snake.
The way in whi h the segment whi h was the tail earlier be omes the head an be handled
in many ways. We do this as follows. We make the erstwhile tail segment be ome a opy
of the erstwhile head. At this point we move the erstwhile tail segment in the dire tion of
motion.
The ode for the lass snake is given in Figure 18.1.
18.4.3 User intera tion
The main point of the example is of ourse how the user intera ts with the snake. This
happens in the main program given below.
The main program sets up the anvas and the snake. It then goes into an endless loop
in whi h every 0.1 se onds the program he ks if the user has typed anything in order to
hange the dire tion of the snake. This is done using the fun tion he kEvent. If the user
has indeed typed a key, then its value is extra ted using the harFromEvent fun tion. This
key is then used as an argument to the member fun tion move of the snake, so that the
movement happens in the required dire tion. If the user did not type anything, then an an
Abhiram Ranade, 2013. Do not distribute 315

onst int gridsep = 20, xinit = 30, yinit = 20, length = 10, npts = 40;

stru t Snake{

stru t Snake{
Cir le body[length℄;
int headindex; // whi h body element is the head of the snake
har dir; // urrent dire tion of motion.
Snake(){ // head at (xinit,yinit) in the oarse grid.
headindex = 0;
for(int i=0; i<length; i++)
body[i℄.reset((xinit+0.5+i)*gridsep, (yinit+0.5)*gridsep, gridsep*0.5);
dir = 'w';
}
void move(){
move(dir); // ontinue along old dire tion
}
void move( har ommand){
if( ommand != 'w' && ommand != 'n' &&
ommand != 'e' && ommand != 's') ommand = dir;
// if user typed illegal letter, keep moving in old dire tion

int newhead = (headindex +length - 1) % length; // old tail


body[newhead℄ = body[headindex℄; // old tail now on top of head
headindex = newhead; // old tail element be omes head

// move new head in dire tion of motion.


if( ommand == 'w') body[headindex℄.move(-gridsep, 0);
else if ( ommand == 'n') body[headindex℄.move(0, -gridsep);
else if ( ommand == 'e') body[headindex℄.move(+gridsep, 0);
else if ( ommand == 's') body[headindex℄.move(0, +gridsep);

dir = ommand; // save new motion dire tion


}
};

Figure 18.1: The Snake lass


Abhiram Ranade, 2013. Do not distribute 316
argumentless form of the move member fun tion is alled, whi h auses the snake to ontinue
in the dire tion whi h it was originally moving.
int main(){
initCanvas("Snake", gridsep*npts, gridsep*npts);
Snake s;
while(true){
XEvent event;
if( he kEvent(event)){
if(keyPressEvent(event)){
har = harFromEvent(event);
s.move( ); // new dire tion?
}
}
else s.move(); // keep moving as before.
wait(0.1);
}
}

18.5 Exer ises


1. Modify the drawing program dis ussed in the hapter so that it \beauti es" what the
user draws. Spe i ally, if the user draws something that nearly looks like a straight
line, you should draw it as a straight line. Or a ir ular ar . Try to ome up with some
proto ols so that the user an draw beautiful pi tures without too mu h e ort.
2. Another use of \dragging", in addition to drawing, is to drag obje ts around on the
s reen. In parti ular, the user an move the ursor to an obje t, then li k a button,
drag the mouse, and nally release the button (drop). This should ause the obje t
to get sele ted and moved and dropped at the new position. This idea will be useful
in building graphi al editors, as you must have seen. Modify the drawing program of
the previous exer ise so that it does not imprint the lines on the anvas, but merely
shows them by reating suitable line and ir le obje ts. Keep tra k of these obje ts in
suitable arrays. Allow them to be dragged and dropped.
3. Add prizes/food/walls to the snake game. Also make the snake's length in rease by
one everytime it eats food. Also assign a s ore to the player depending upon how mu h
food/prizes the snake has eaten, and even just how long the snake has stayed around.
Display the s ore suitably.
Chapter 19

Representing variable length entities

We ontinue with the idea of building lasses to represent entities that we might want in our
programs. In many ases, the entities we wish to represent do not have a standard length, e.g.
a pie e of text su h as the name of a person. Indeed, human beings have names whi h an
be very short or very long. We may also wish to represent entities su h as polygons, where
the number of verti es might be di erent, or polynomials, where the number of oeÆ ients
might be di erent. We may also be alled upon to represent graphs (e.g. road networks) or
the set of sets of students in di erent lasses; in general we might want to represent several
instan es of ea h su h olle tions, and the instan es will typi ally have di erent lengths.
One natural strategy is to allo ate the maximum possible length to represent the entity in
question. We used this idea for representing text strings in Se tion 14.1: if we want to store
names of people, we allo ated har arrays of what we supposed was the maximum possible
length. This learly uses memory ineÆ iently. People have names of widely varying lengths,
e.g. the a tor Om Puri and the freedom ghter/s holar Chakravarti Rajagopala hari. So in
general we will be for ed to allo ate long arrays, but most of the time we will use only small
portions of these.
In this hapter, we will see how to design a data type for storing text strings, su h that it
does not waste memory. We annot dire tly use stru tures/ lasses/arrays the way we have
des ribed them so far. This is be ause the size of a lass/stru ture/array must be xed on e
for all, typi ally without the knowledge of the size of the text string to be stored in it. The
most onvenient way of representing entities whose size is not known when we write the
program is to use the so alled heap memory allo ation. This is also referred to as dynami
memory allo ation. Using this heap memory, we will onstru t a String lass using whi h
you will be able to store and manipulate text strings eÆ iently and onveniently.
In general the heap memory will be useful in building representations for entities whose
sizes may not be known at the time of writing the program, or whose sizes may even vary
over time. We will see examples of su h representations in the Exer ises.
The Standard Library of C++ ontains several lasses whi h use heap memory to a -
ommodate entities of variable sizes. In fa t one of the lasses in the library is a string
lass, whi h an be onsidered to be an advan ed version of the String lass we dis uss in
this hapter. We will study the Standard Library in luding the string lass in Chapter 20.
Chapter 20 will not dis uss how these lasses are implemented; however the implementation
of the String lass in this hapter will provide some lues.

317
Abhiram Ranade, 2013. Do not distribute 318
19.1 The Heap Memory
So far, for the most part, we have been onsidering variables that have been allo ated in
the a tivation frame of some fun tion or another. Su h variables are present only for the
duration in whi h the orresponding fun tion is exe uting. 1

However, a C++ program an also be given memory outside of a tivation frames. A


ertain region of memory is reserved for this purpose. This region is alled the heap memory,
or just the heap. You an request memory from the heap by using the operator new. Suppose
T is a data type su h that ea h variable of type T requires s bytes of storage. Then the
expression
new T
auses a variable of type T, or in other words s bytes of memory, to be allo ated in the
heap, and the expression itself evaluates to the address of the allo ated variable. To use this
allo ated variable, you must save the address { this you an do typi ally by storing it in a
variable of type pointer to T. More generally, we may write
new all-to-a- onstru tor-for-T
This will not just reate a variable of type T, but it will also be initialized using the given
onstru tor.
Thus, for the Book type as de ned in Se tion 15.1, we ould write:
Book *p;
p = new Book;
The rst statement de lares p to be of type pointer to Book. The se ond statement requests
allo ation of memory from the heap for storing a Book variable. The address of the allo ated
memory is pla ed in p. We ould of ourse have done this in a single statement if we wish,
by writing Book *p = new Book;. The memory allo ated an be used by dereferen ing the
pointer p, i.e. we may write
p->pri e = 335.00;
p->a essionno = 12345;
to set the pri e and a ession number respe tively.
The se ond form of the new operator allows us to allo ate an array in the heap. Again,
if T is a type then we may write
T *q = new T[n℄;
whi h will allo ate memory in the heap for storing an array of n elements of type T, and the
address of the allo ated array would be pla ed in q. We an a ess elements of the array
starting at q by using the [℄ operator as dis ussed in Se tion 13.3.3. Thus we ould write
q[i℄ where i must be between 0 and n (ex lusive). Note that T ould be a fundamental
data type, or a lass. If it is a lass, ea h obje t T[i℄ would be onstru ted by alling the
Other than this, there are the global variables. They have to be essentially allo ated before the program
1
begins exe ution, and hen e are not interesting for the purpose of this dis ussion.
Abhiram Ranade, 2013. Do not distribute 319
onstru tor whi h does not take any arguments. You must ensure that su h a onstru tor is
available.
Note that allo ating memory in this manner is a somewhat involved operation. There is
some bookkeeping needed to be done so that subsequently the same memory is not allo ated
for another request, until we expli itly free the memory. We an free memory, i.e. return it
ba k to the heap by using the operator delete. Thus, we might write:
delete p;

Assuming p pointed to memory allo ated as above, delete p; would ause the memory to
be returned ba k, i.e. somewhere it would be noted that the memory starting at p is now
free and may be allo ated for future requests. The delete[℄ operator is used if an array
was allo ated. So for q as de ned earlier, we may write:
delete[℄ q;
Note that on e we exe ute delete (or delete[℄) it is in orre t to a ess the orresponding
address; it is almost akin to entering a house we have sold just be ause we know its address
and perhaps have a key to it. It does not belong to us! Someone else might have moved in
there, i.e. the allo ator might have allo ated that memory for another request. A essing
su h a pointer is said to ause a dangling pointer error.
We used the phrase allo ator above. By this we mean the set of (internal) fun tions and
asso iated data that C++ maintains to manage heap memory. These are the fun tions that
get alled (behind the s enes, so to say) when you ask for memory using the new operator
and release memory using the delete operator.
19.1.1 A detailed example
We present a detailed example of how heap memory might get allo ated during exe ution.
Consider the program of Figure 19.1 (a). We will assume for sake of de niteness that
the heap starts at address 24000. When the exe ution starts, all the memory in the heap is
available.
When the rst statement, int* intptr = new int; is exe uted, memory to store a
single int is given from the beginning of the heap. Sin e an int requires 4 bytes, the 4 bytes
with address 24000 to 24003 are reserved, and the address of the rst of these bytes, 24000,
is returned and stored in intptr. Next, memory for an array of 3 hara ters is requested.
For this the next 3 bytes are reserved, starting at 24004. Thus ptr gets the value 24004.
The following statement *intptr = 279; stores the number 279 into the allo ated mem-
ory pointed to by intptr, i.e. at address 24000. The next 3 statements store the hara ter
string onstant "ab" into the array pointed to by ptr. At this stage of the exe ution, the
memory asso iated with the program is in two parts: the a tivation frame whi h ontains
the variables intptr and ptr, and the memory whi h has been allo ated in the heap.
Figure 19.1(b) shows the a tivation frame. The heap is shown in Figure 19.1( ).
Abhiram Ranade, 2013. Do not distribute 320

int main(){
Heap memory
int* intptr = new int;
Address Content
har* ptr = new har[3℄;
24000
*intptr = 279;
24001 279
ptr[0℄ = 'a';
24002
ptr[1℄ = 'b';
24003
ptr[2℄ = '\0';
24004 'a'
}
24005 'b'
24006 0
(a) 24007
24008
24009
AF of main() 24010
intptr : 24000 24011
ptr : 24004 24012 :::
(b) ( )
Figure 19.1: (a) Program, (b) A tivation Frame at end, ( ) Heap area at end
19.1.2 Lifetime and a essibility
We have said earlier that if a variable is reated in the a tivation frame, then it is destroyed
as soon as the ontrol exits from the on erned fun tion. In fa t, the rule is more stringent:
a variable is destroyed as soon as ontrol leaves the blo k in whi h the variable is reated.
Variables reated in the heap are di erent. Exiting from a blo k, or returning from
fun tions does not ause them to be destroyed: they an only be destroyed by exe uting the
delete operations.
The se ond point on erns how the variables on the heap are a essed. They are not
given a name, but are a essible only through its address! So it is vital that we do not lose
the address. Thus we must not overwrite the pointer ontaining the address of a variable
allo ated in the heap, unless we stored the address in some other pointer as well. If we do
overwrite a pointer ontaining the address of a heap variable, and there is no other opy,
then we an no longer a ess the memory area whi h has been given to us. The memory
area has now be ome ompletely useless. This is te hni ally alled a memory leak. We must
not let memory leak, we must instead return it using the delete operator so that it an be
reused!

19.2 Representing text: a preliminary implementation


We now show how to use heap allo ation for representing text strings. The key idea is that
the text itself will be stored in an array whi h we will allo ate on the heap. To make the
dis ussion more on rete, suppose we want an implementation using whi h we an write a
main program like the following.
Abhiram Ranade, 2013. Do not distribute 321
int main(){
String a,b;
a = "pqr";
b = a;
String = a + b; // should on atenate a, b.
.print(); // should print on s reen

String d[2℄; // array of 2 strings


d[0℄ = "xyz";
d[1℄ = d[0℄ + ;
d[1℄.print();
}
Other operations might also be desirable for this lass, we dis uss those later.
19.2.1 The basi storage ideas
Here is the de laration of a lass String whi h will enable us to write the main program
above.
lass String{
har* ptr; // will point to address in heap where a tual text is stored.
publi :
String();
void print();
void operator=( har* rhs);
void operator=(String rhs);
String operator+(String rhs);
};
The lass ontains just one data member, ptr whi h is meant to point to the starting address
in the heap memory where the text asso iated with the variable is stored. Spe i ally, we
will store the text, terminated by a null hara ter (i.e. 'n0') in the heap memory. This way,
we will not need to store the length of the allo ated region expli itly. Further, if a String
variable ontains the empty string, we will set its member ptr to NULL.
In prin iple, if two String variables have the same value, i.e. ontain the same text, then
potentially we an store a single opy of that text in the heap, and have the ptr members
of both the variables point to that opy. While this sharing will likely save memory, it will
also ompli ate the logi we will need to use to ask for and release heap memory. So we will
adopt the simpler idea: the text asso iated with every variable will be stored in a distin t
area in the heap memory.
19.2.2 Constru tor
Initially, when we reate a string variable, we want it to hold the empty string. Hen e the
onstru tor is as follows.
Abhiram Ranade, 2013. Do not distribute 322
String::String(){
ptr = NULL;
}

19.2.3 The print member fun tion


We next dis uss the member fun tion print. This is very simple.
void String::print(){
if(ptr != NULL) out << ptr << endl;
else out << "NULL" << endl;
}
Sin e ptr gives the address from where the string is stored, it suÆ es to write out << ptr
<< endl;. However, if ptr is NULL, then we annot print it, instead we must expli itly print
out "NULL".
19.2.4 Assignments
We dis ussed in Chapter 15 that assignment is already de ned for stru ture types, provided
the right hand side of the assignment is also a stru ture of the same type as the left hand
side. Su h a statement exe utes by opying ea h data member of the right hand side to the
orresponding member of the left hand side. We will see that this is not adequate for our
purpose. In addition, our String data type allows the right hand side to be of type har*.
This we will have to de ne afresh. This is what we onsider rst.
As dis ussed in Se tion 16.6, we an de ne a member fun tion operator= to spe ify how
assignment should work. Sin e the right hand side is to be of type har*, this member
fun tion must have a har* parameter. In the body of the fun tion we des ribe what we
want to happen to exe ute the assignment. We an de ne this as follows.
void String::operator=( har *rhs){
delete [℄ ptr;
ptr = new har[length(rhs) + 1℄;
str py(ptr,rhs);
}
We give an example to see how this will work. Suppose z is of type String and say we have
a statement
z = "mno";
This statement will ause the member fun tion operator= to exe ute, with the variable z
being the re eiver, and the parameter rhs being the address of the text string "mno".
Note that the variable z may already ontain some value before ontrol arrives at the
assignment statement, say the variable z ontains the text "pqr". In this ase, before our
assignment statement, z.ptr will already be pointing to a heap region storing "pqr". When
we set z.ptr to point to the area storing "mno", the area ontaining "pqr" will no longer be
Abhiram Ranade, 2013. Do not distribute 323
needed, and hen e an be deleted. This is what the rst statement in the fun tion does.
After that we request memory from the heap enough to store the new value, i.e. as many
bytes as the number of hara ters in rhs plus an extra byte to store the null hara ter.
For this, we have used the length fun tion from Se tion 14.1.3. After that we opy the
text pointed to by rhs into the new region. In this we have used the fun tion str py from
Se tion 14.1.3.
Next we onsider assigning one string to another as in the statement b = a; to exe ute,
we need to do something mu h like above. The only di eren e is that the right hand side of
the assignment is a String rather than a har*. The text that is needed to be opied now
omes from taking the ptr member of the right hand side, rather than taking the right hand
side itself dire tly.
void String::operator=(String rhs){
delete [℄ ptr;
ptr = new har[length(rhs.ptr) + 1℄;
str py(ptr,rhs.ptr);
}

19.2.5 De ning operator +


Next we onsider how the operation a + b is to be performed on String variables. We
ould write this as an ordinary fun tion operator+ taking two String arguments; or we
ould write it as a member fun tion to be invoked on the left hand side String, with the
right hand side being supplied as an argument. This fun tion is required to return a String
variable holding the on atenation of the text in the operands.
String String::operator+(String rhs){
String res;
res.ptr = new har[length(ptr) + length(rhs.ptr) + 1℄;
str py(res.ptr, ptr);
str py(res.ptr, rhs.ptr, length(ptr));
return res;
}
The result will be al ulated as the String res. It has to hold text of length equal to the
sum of the texts of the left hand side, i.e. the text in the impli it argument, of length
length(ptr), and the text in the rhs argument, of length length(rhs.ptr), and an extra
byte to hold the null hara ter. So the se ond statement requests memory of this size in
the heap. Then the text in the impli it argument is opied into res.ptr using the fun tion
str py. The se ond str py all above assumes that there exists a str py fun tion taking
3 arguments as follows.
void str py( har destination[℄, har sour e[℄, int dstart=0){
int i;
for(i=0; sour e[i℄ != '\0'; i++)
destination[dstart+i℄=sour e[i℄;
destination[dstart+i℄=sour e[i℄; // opy the '\0' itself
}
Abhiram Ranade, 2013. Do not distribute 324
As you an see this will opy the sour e string to the destination starting at index dstart,
This nishes the de nition of the String lass. With this the main program given in the
beginning an be exe uted.

19.3 Advan ed topi s


The String lass as de ned in the previous se tion is enough for the main program given
at the beginning of the se tion (Se tion 19.2). However, the de nition will not allow us to
do many other operations that we might want, e.g. pass String obje ts as arguments to
fun tions by value, or return String obje ts as results. How to enable these operations is
the subje t of this se tion.
We begin by xing a short oming of the existing de nition of String. Turns out that
we will have a memory leak if we allo ate a String variable inside a blo k:
{
String s;
s = "pqr";
}
This is be ause when the blo k ends, the obje t s will be deallo ated from the urrent
a tivation frame. As a result we will no longer be able to use the memory pointed to by
s.ptr. So ideally we should delete[℄ that memory at the end of every blo k. We ould
do this by writing the statement delete[℄ s.ptr; before the end of the blo k. Having to
write this ourselves for every su h variable and every su h blo k is in onvenient and error
prone (we might forget). But also note that ptr is a private member, so to delete it from
outside the lass de nition we will need some further modi ation to our lass de nition.
This is where destru tors ome in handy.
19.3.1 Destru tors
A String obje t will be deallo ated when ontrol exits the blo k in whi h it is de ned. This
is ne, however, we would like the memory pointed to by the member ptr to also be returned
ba k to the heap when the obje t is deallo ated. We an do this by de ning a destru tor for
String.
String::~String(){
delete[℄ ptr;
}
C++ will all the destru tor on any variable that is about to be dello ated, and a tually
deallo ate it only after the destru tor exe ution nishes. When the destru tor above is
alled, it will return the memory pointed to by ptr ba k to the heap, as we wish.
Remember that the destru tor all happens impli itly. So you should never expli itly all
the destru tor be ause then it will end up being alled twi e, with ptr being deleted twi e,
whi h is erroneous.
Note that if we do not supply a destru tor, C++ itself de nes a destru tor that does
nothing. In this ase, the memory pointed to by ptr will not be returned to the heap, thus
ausing a memory leak.
Abhiram Ranade, 2013. Do not distribute 325
19.3.2 Copy onstru tor
A opy onstru tor is a onstru tor, whi h initializes the obje t being reated to be a opy
of an existing obje t of the same lass, supplied as the argument. It has some spe ial uses
whi h we will onsider; but we rst note that it an be written in the natural manner.
String::String( onst String &rhs){
ptr = new har[length(rhs.ptr)+1℄;
str py(ptr,rhs.ptr);
}
The opy onstru tor is essentially like the assignment operator; however sin e the left hand
side is just being onstru ted, it an be simpler than an assignment operator. When assigning
a String x to String y, i.e. for y = x, we need to perform delete[℄ on y be ause what it
points to will no longer be needed. However, if y is just being onstru ted, then we know that
its ptr member does not point to anything yet. So a delete operation is not needed. Hen e
the above ode does not ontain a delete[℄ ptr operation while the assignment operator
of Se tion 19.2.4 does.
Note that the parameter for the opy onstru tor must be passed by referen e, the reason
for this will be ome lear shortly. Another important point is that it is most natural that
when you opy an existing obje t to onstru t a new obje t, you will likely not modify the
existing obje t. So it is appropriate to make the onstru tor parameter onst.
A opy onstru tor an be alled expli itly by the user; however there are 3 situations
when it is used by the ompiler.
1. When you de ne an obje t and assign another obje t to it at the time of de nition,
e.g. if you write:
String s = "ab ";
String t = s;

Then to opy s into t the opy onstru tor is used, and not the assignment operator,
i.e. member fun tion operator=.
2. When an obje t is passed to a fun tion by value.
3. When an obje t is returned from a fun tion.
Thus by de ning the opy onstru tor yourself, you an ontrol how the three operations
above happen! If you do not de ne a opy onstru tor, C++ supplies you one, and that
merely opies members. Clearly, su h a default opy onstru tor will not be appropriate for
String.
You will now see that it is not appropriate to pass the argument to a opy onstru tor
by value. If you indeed pass it by value, then it would have to be rst opied, but for that
you would have to invoke the opy onstru tor, and so on. Thus we would have in nite
re ursion. In fa t if you write a opy onstru tor whi h takes an argument by value, C++
will ag it as an error.
Abhiram Ranade, 2013. Do not distribute 326
19.3.3 The [℄ operator
We would also like to a ess individual hara ters in a string by spe ifying the index. You
already know from Se tion 13.3.3 that [℄ is an operator. We just have to overload it for the
String lass!

har& String::operator[℄(int i){ // returning a referen e.


return ptr[i℄;
}
Note that we are returning a referen e to ptr[i℄, not the value of ptr[i℄. Thus we an use
it on the left hand side of the assignment statement as well.
19.3.4 An improved assignment operator
We an improve our assignment operator slightly to allow multiple assignments in the same
statement, i.e. allow us to write something like
String s,t,u;
s = t = u = "ab ";
For this to happen, we merely have to return a referen e to the left hand side. Thus a ni er
de nition of the assignment operator is as follows.
String& String::operator=( onst String &rhs){
delete [℄ ptr;
ptr = new har[length(rhs.ptr) + 1℄;
str py(ptr,rhs.ptr);
return *this;
}
We have also passed the rhs parameter by referen e.
19.3.5 Use
Figure 19.2 shows the new de nitions together. We have also in luded member fun tion
size whi h gives the number of hara ters in the string, and the indexing operator, [℄.
Using this the following fun tion and main program alling it an now be written.
String l ase( onst String &arg){
String res = arg;
for(int i=0; i<res.size(); i++)
if(res[i℄ >= 'A' && res[i℄ <= 'Z') res[i℄ += 'a' - 'A';
return res;
}

int main(){
String a,b;
Abhiram Ranade, 2013. Do not distribute 327
a = "PQR";
b = a;
String = a + b; // should on atenate a, b.
.print(); // should print on s reen

String d[2℄; // array of 2 strings


d[0℄ = "Xyz";
d[1℄ = l ase(d[0℄ + );
d[1℄.print();
d[1℄[2℄ = d[0℄[1℄;
d[1℄.print();
}
This will rst print , whi h will have the value "PQRPQR". The se ond print statement will
on atenate "Xyz" and "PQRPQR" and then onvert it all to lower ase. Thus "xyzpqrpqr"
will get printed. After that we will set the hara ter at index 2 of d[1℄ to the hara ter at
index 1 of d[0℄. Thus the last print statement will print "xyypqrpqr".

19.4 Remarks
We have shown how we an de ne a data type String to store hara ter strings. We showed
that the de nition was good enough to allow reating strings, indexing into them, on ate-
nating them, assigning to strings, passing strings to fun tions, and returning them from
fun tions. E e tively, using our de nition, we have an illusion that String is a fundamen-
tal data type. Our implementation guarantees that the obje ts we reate will use memory
eÆ iently. 2

There is, however, one operation that we should not perform on the String lass. This
is the operation of allo ating a String obje t itself in heap memory. Thus we should not
write something like
Poly *ptr = new String; // !!! DO NOT DO THIS !!!
If this is inside a blo k, then on exit from the blo k the variable ptr will get deallo ated.
As a result, the memory area it points to will leak away.
The key point is that the way the String lass is de ned, you will not need to worry
about allo ating memory. Indeed, you an use the String lass without having to know
about the heap. You are not expe ted to worry about managing the heap; memory will
get allo ated for you when needed, it will also get deallo ated when needed. All this will
happen behind the s enes. You are expe ted to sit ba k and enjoy the onvenien e, without
interfering in the memory management.
19.4.1 Class invariants
While designing String, we made some important de isions early on. In parti ular we said
that there will be a separate opy in the heap memory of the value stored in ea h String
Ex ept that if two variables of type String have the same value, we will keep two opies of the value.
2
This an be improved upon, as dis ussed in Appendix B.
Abhiram Ranade, 2013. Do not distribute 328

lass String{
har* ptr; // will point to address in heap where a tual text is stored.
publi :
String(){ ptr = NULL; }
String( onst String &rhs){
ptr = new har[length(rhs.ptr)+1℄;
str py(ptr,rhs.ptr);
}
String& operator=( onst har* rhs){
delete [℄ ptr;
ptr = new har[length(rhs) + 1℄;
str py(ptr,rhs);
return *this;
}
String& operator=( onst String &rhs){
delete [℄ ptr;
ptr = new har[length(rhs.ptr) + 1℄;
str py(ptr,rhs.ptr);
return *this;
}
String operator+(String rhs){;
String res;
res.ptr = new har[length(ptr) + length(rhs.ptr) + 1℄;
str py(res.ptr, ptr);
str py(res.ptr, rhs.ptr, length(ptr));
return res;
}
void print(){
if(ptr != NULL) out << ptr << endl;
else out << "NULL" << endl;
}
int size(){return length(ptr);}
har& operator[℄(int i){return ptr[i℄;}
};

Figure 19.2: The omplete String lass


Abhiram Ranade, 2013. Do not distribute 329
obje t. Su h a property that the members of a lass possess throughout their lifetime, is
sometimes alled a lass invariant. It is useful to learly write down su h invariants, as you
have seen, they guide the implementation of the lass.

19.5 Exer ises


1. Consider the following ode. Identify all errors in it.
int *ptr1, *ptr2, *ptr3, *ptr4;
ptr1 = new int;
ptr3 = new int;
ptr4 = new int;
ptr2 = ptr1;
ptr3 = ptr1;
*ptr2 = 5;
out << *ptr2 << *ptr1 << endl;
delete ptr1;
out << *ptr3 << *ptr4 << endl;

The possible errors are: memory leaks, dangling pointers (a essing memory that was
allo ated to us earlier but has sin e been deallo ated), and referring to uninitialized
variables.
2. Suppose you have a le that ontains some unknown number of numbers. You want to
read it into memory and print it out in the sorted order. Develop an extensible array
data type into whi h you an read in values. Basi ally, the real array should be on the
heap, pointed to by a member of your stru ture. If the array be omes full, you should
allo ate a bigger array. Be sure to return the old unused portion ba k to the heap.
Write opy onstru tors et . so that the array will not have leaks et .
3. De ne a lass for representing polynomials. In lude member fun tions for addition,
subtra tion, and multipli ation of polynomials. Ensure that your implementation
obeys a lass invariant in the style of Se tion ??.
4. De ne the modulo operator % for polynomials. Suppose S (x); T (x) are polynomials,
then in the simplest de nition, the remainder S (x) mod T (x) is that polynomial R(x)
of degree smaller than T (x) su h that S (x) = T (x)Q(x) + R(x) where Q(x) is some
polynomial.
The main motivation for writing the modulo operator is to use it for GCD omputation
later. So it is important to make sure that there are no round-o errors as would happen
if you divide. One way around this is to de ne the remainder S (x) mod T (x) to be
any kR(x) where k is any number, where R(x) is as de ned above. Assuming that the
oeÆ ients of the polynomials are integers to begin with, you should now be able to
ompute a remainder polynomial without division. Hen e there will be no round o
either. Of ourse this has the drawba k that the oeÆ ients will keep getting larger.
For simpli ity ignore this drawba k.
Abhiram Ranade, 2013. Do not distribute 330
5. In this assignment you are to write a lass using whi h you an represent and ma-
nipulate sets of non-negative integers. Spe i ally, you should have member fun tions
whi h will (a) enable a set to be read from the keyboard, (b) onstru t the union of
of two sets, ( ) onstru t the interse tion of two sets, (d) determine if a given integer
is in a given set, (e) print a given set. Use an array to store the elements in the set.
Do not store the same number twi e. With your fun tions it should be possible to run
the following main program.
main(){
Set a,b;
a.read();
b.read();

set = union(a,b);
set d = interse tion(a,b);

int x;
in >> x;

bool both = belongs(x,d);


bool none = !belongs(x, );

if( both ) {
out << x << " is in the interse tion ";
.print();
}
else if (none) out << x << " is in neither set." << endl;
else out << x << " is in one of the sets." << endl;
}

The fun tion Set::read will be very similar/identi al to Poly::read. For the rest,
ensure that you allo ate arrays of just the right size by rst determining the size of the
union/interse tion.
6. Eu lid's GCD algorithm works for nding the GCD of polynomials as well. Write the
ode for this, using the iterative expression as well as the re ursive expression. Will
both versions ause the same number of heap memory allo ations? Whi h one will be
better if any?
7. Consider the following new member fun tion for the lass Poly:
void move(Poly &dest);

When invoked as sour e.move(dest), it should move the polynomial ontained in


sour e to dest, and also set sour e to be unde ned. E e tively, this is meant to be
an assignment in whi h the value is not opied but it moves. Is it ne essary to allo ate
Abhiram Ranade, 2013. Do not distribute 331
new memory while implementing move in order to make sure that the lass invariant
holds?
See if the Poly lass with the new move fun tion will improve the GCD programs
onsidered earlier.
8. Templetize the g d fun tion so that it an work with ordinary numbers as well as poly-
nomials. You will have to de ne a few more member fun tions as well as a onstru tor.
Note that int is a onstru tor for the int type, i.e. int(1234) returns the integer
1234.
9. Consider the lass de ned as follows.
onst int QUEUESIZE = 10;

lass Queue{
int front;
int nWaiting;
int elements[QUEUESIZE℄;
Queue(){front = nWaiting = 0;}
Queue(Queue &q){}
Queue & operator= (Queue & other){ return *this; }
publi :
stati Queue* reate(){ return new Queue(); }
bool insert(int value){
if(nWaiting == QUEUESIZE) return false; // queue is full
elements[(front + nWaiting) % QUEUESIZE℄ = value;
nWaiting++;
return true;
}
int remove(){
if(nWaiting == 0) return -1; // queue is empty
int item = elements[front℄;
front = (front + 1) % QUEUESIZE;
nWaiting--;
return item;
}
~Queue(){if (nWaiting > 0) out << "Non empty queue destroyed.\n";}
};

This de nition of Queue is designed to be used in some unusual ways. State what
operations it allows, and what it does not allow. Dis uss the rationale for these unusual
features. Rewrite the taxi dispat h program using it.
Chapter 20

The standard library

An important prin iple in programming is to not repeat ode: if a single idea is used re-
peatedly, write it as a fun tion or a lass, and invoke the fun tion or instantiate a lass
obje t instead of repeating the ode. But we an do even better: if some ideas are used
outstandingly often, perhaps the language should give us the fun tions/ lasses already! This
is the motivation behind the development of the standard library, whi h you get as a part
of any C++ distribution. It is worth understanding the library, be ause familiarity with it
will obviate the need for a lot of ode whi h you might otherwise have written. Also, the
fun tions and lasses in the library use the best algorithms, do good memory management
if needed, and have been extensively tested. Thus it is strongly re ommended that you use
the library whenever possible instead of developing the ode yourself.
The library is fairly large, and so we will only take a small peek into it to get the avour.
We will begin with the string lass, whi h is very onvenient for storing text data. This
lass is an advan ed version of the String lass of Chapter 19. It is extremely onvenient,
and you should use it by default instead of using hara ter arrays.
Next we will study the template lasses ve tor and map whi h are among the so alled
ontainer lasses supported in the library. They an be used to hold olle tions of obje ts,
just as arrays an be. Indeed you may think of these lasses as more exible, more powerful,
extensions of arrays. We will not dis uss how any of these lasses are implemented, although
you an get some lues from the dis ussions in Chapter 19 and Se tion 22.2. But of ourse,
as users you only need to know the spe i ation of the lasses, and need not worry about
how they are implemented.
As examples of the use of the standard library, we program variations on the marks
display program of Se tion 13.2.2. You know enough C++ to solve all these variations,
and you have already solved some of them. However, you will see that using the Standard
Library, you will be able to solve them with mu h less programming e ort.
At the end of the hapter we will give a qui k overview of the other lasses in the standard
library. Of these, we will use the priority queue lass in Chapter 25.

20.1 The string lass


The string lass is a very onvenient lass for dealing with har data. It is so onvenient,
that you are en ouraged to use the string lass wherever possible, instead of har arrays.
332
Abhiram Ranade, 2013. Do not distribute 333
To use the string lass you need to in lude the header le <string>, but note that it will be
in luded automati ally as a part of <simple pp>.
We an reate string obje ts p,q,r very simply.
#in lude <string> // not ne essary if simple pp is in luded.

string p = "ab ", q ="defg", r;


r = p;

The rst statement will de ne variables p, q, r and initialize them respe tively to "ab ",
"defg" and the empty string respe tively. The se ond statement opies string p to string r.
When you make an assignment, the old value is overwritten. Noti e that you do not have to
worry about the length of strings, or allo ate memory expli itly.
You an print strings as you might expe t.
out << p << "," << q << "," << r <<endl; //prints ``ab ,defg,ab ''

This will print out the strings separated by ommas. Reading in is also simple, in >> p;
will ause a whitespa e terminated sequen e of the typed hara ters to be read into p. To
read in a line into a string variable p you an use
getline( in, p);
Note that you annot write in.getline(p) as you might expe t from your experien e with
har* variables. Also see the variation des ribed an used in Se tion 20.5.1.
The addition operator is de ned to mean on atenation for strings. Thus given the
previous de nitions of p,q,r you may write
r = p + q;
string s = p + "123";
This will respe tively set r,s to "ab defg" and "ab 123". The operator += an be used to
append.
You an write s[i℄ to denote the ith hara ter of string s. Member fun tions size
and length both return the number of hara ters in the string. Many other useful member
fun tions are also de ned. Here are some examples.
s[2℄ = s[3℄; // indexing allowed. s will be ome ab1123.
out << r.substr(2) // substring starting at 2 going to end
<< s.substr(1,3) // starting at 1 and of length 3
<< endl; // will print out `` defgb11'', assuming r, s as above

int i = p.find("ab"); // find from the beginning


int j = p.find("ab",1); // find from position 1.
out << i << ", " << j << endl; // will print out 0, 3

Note that if the given string is not found, then the find operation returns the onstant
string::npos. We an use this as follows:
Abhiram Ranade, 2013. Do not distribute 334
string t; getline( in, t);
int i = p.find(t);
if(i == string::npos)
out << "String: "<< p << " does not ontain "<< t << endl;
else
out << "String: "<< p << " ontains "<< t << " from position "<< i << endl;
Finally, we should note that strings have an order de ned on them: the lexi ographi order,
i.e. the order in whi h the strings would appear in a di tionary. One string is onsidered
< than another if it appears earlier in the lexi ographi al order. Thus we may write the
omparison expressions p == q or p < q or p >= q and so on for strings p,q with the
natural interpretation.
20.1.1 Passing strings to fun tions
Sin e string is a lass, we an pass it to fun tions using value, in whi h ase a new opy is
passed, or by referen e, in whi h ase the alled fun tion operates on the argument itself.
20.1.2 A detailed example
In Se tion 20.5.1 we will see a detailed example of string manipulation.

20.2 The template lass ve tor


The template lass ve tor is meant to be a friendlier, more general variation of one dimen-
sional arrays. To use the template lass ve tor you need to in lude a header le:
#in lude <ve tor>
A ve tor an be reated by supplying a single template argument, the type of the elements.
For example, we may reate a ve tor of int and a ve tor of float by writing the following.
ve tor<int> v1;
ve tor<float> v2;

These ve tors are empty as reated, i.e. they ontain no elements. But other onstru tors
are available for reating ve tors with a given length, and in addition, a given value. For
example, you might write:
ve tor<short> v3(10); // ve tor of 10 elements, ea h of type short.
ve tor< har> v4(5,'a'); // ve tor of 5 elements, ea h set to 'a'.
ve tor<short> v5(v3); // opy of v3.
A ve tor keeps tra k of its own size, to know the size you simply use the member fun tion
size. Thus
v3.size()
Abhiram Ranade, 2013. Do not distribute 335
would evaluate to 10, assuming the de nition earlier. You an a ess the ith element of a
ve tor using the subs ript notation as for arrays. For example, you ould write
v3[6℄ = 34;
v4[0℄ = v4[0℄ + 1;
The usual rules apply, the index must be between 0 (in lusive) and the ve tor size (ex lusive).
You an also extend the ve tor by writing:
v1.push_ba k(37);
v3.push_ba k(22);
These statements would respe tively in rease the length of v1 to 1, and of v3 to 11. The
argument to the method push ba k would onstitute the last element.
A whole bun h of operations an be performed on ve tors. For example, unlike arrays,
you an assign one ve tor to another. So if v,w are ve tors of the same type, then we may
write
v = w;
whi h would make v be a opy of the ve tor w. The old values that were ontained in v are
forgotten. This happens even if v,w had di erent lengths originally. You should realize that
although the statement looks very small and simple, all the elements are opied, and hen e
the time taken will be roughly proportional to the length of w.
You an shrink a ve tor by one element by writing v.pop ba k(). But you an also set
the size arbitrarily by writing:
v.resize(newSize);
w.resize(newSize,newValue);
The rst statement would merely hange the size. The se ond statement would hange the
size, and if the new size is greater, then the new elements would be assigned the given value.
20.2.1 Inserting and deleting elements
It is possible to insert and delete elements from the middle of a ve tor. This is dis ussed in
Se tion 20.6.2
20.2.2 Index bounds he king
Instead of using subs ripts [℄ to a ess elements, you an use the member fun tion at. This
will rst he k if the index is in the range 0 (in lusive) to array size (ex lusive). If the index
is outside the range, the program will halt with an error message. Note that the at fun tion
an be used on the left as well as the right hand side of assignments.
ve tor<int> v;
for(int i=0; i<10; i++) v.push_ba k(i*10);

v.at(0) = v.at(1);
This will ause the rst element to be opied to the zeroth, i.e. at the end v will ontain 10,
10, 20, 30, 40, 50, 60, 70, 80, 90.
Abhiram Ranade, 2013. Do not distribute 336
20.2.3 Fun tions on ve tors
A ve tor an be passed to fun tions by value or by referen e. Be ause a ve tor is a lass,
if passed by value the entire ve tor is opied, element by element. Thus the alled fun tion
gets a new opy, and the the alled fun tion an make modi ations only to the opy and
not the original. However, when passed by referen e, the alled fun tion gets a ess to the
original and the values in the original may be read or modi ed.
Here are fun tions to read values into a ve tor and print values in the ve tor. We have
onsidered ve tors of int in this example.
void print(ve tor<int> v){
for(unsigned int i=0; i<v.size(); i++) out << v[i℄ <<' ';
out << endl;
}
void read(ve tor<int> &v){
for(unsigned int i=0; i<v.size(); i++) in >> v[i℄;
}

int main(){ve tor<int> v(5); read(v); print(v);}

We may of ourse templatize the fun tions, e.g.


template< lass T>
void print(ve tor<T> v){
for(unsigned int i=0; i<v.size(); i++) out << v[i℄ <<' ';
out << endl;
}

20.2.4 Ve tors of user de ned data types


We an make ve tors of obje ts of lass T, so long as the lass T has an assignment operator,
a opy onstru tor and a destru tor de ned. This is be ause the ve tor lass will all these
member fun tions internally. So for example, you may write
ve tor<V3> v3ve ;
ve tor<Cir le> ir les;
where V3 is the lass from Chapter 15, and Cir le from Chapter 5. You an also make
ve tors of pointers.
ve tor<Cir le*> ir leve ; // allowed.

20.2.5 Multidimensional ve tors


Sin e the template parameter in a ve tor names a type, by spe ifying that as a ve tor we
an get a ve tor of ve tors, i.e. equivalent of a two dimensional array.
ve tor<ve tor<int> > v;
Abhiram Ranade, 2013. Do not distribute 337
This simply de nes v to be a zero length ve tor of zero length ve tors. Noti e the spa e
between the two > hara ters. Without this spa e the two > hara ters would be interpreted
as the input extra tion operator >>.
Here is how we might de ne a length 10 ve tor of length 20 ve tors, i.e. a 10  20 matrix.
ve tor<ve tor<int> > w(10, ve tor<int>(20));
In this we have used the two argument onstru tor for ve tors, the rst argument, 10 spe i es
the length, and the se ond element, ve tor<int>(20) gives the value of ea h element. But
this value is itself a ve tor of length 20. Thus we get a 10 by 20 matrix represented.
We an a ess the elements of the matrix in the usual manner, i.e. by writing w[i℄[j℄.
However, we may also modify whole rows if we wish. Thus for w as de ned above, we write:
w[0℄ = ve tor<int>(5);
we will hange w to be ome a pe uliar stru ture: it will have 10 rows; the rst will have 5
elements, and the remaining will ontinue to have 20 elements.
This exibility is very useful. Often in s ienti omputing, we en ounter matri es of
ertain shapes, e.g. lower triangular matri es. In a lower triangular matrix, all elements
above the main diagonal are 0. Thus we need not even store them. So we an reate a
ve tor of ve tors in whi h the ith ve tor (i starting at 0) having length i+1. This is an easy
exer ise.
On the one hand, the exibility des ribed above is useful, but on the other, reating a
matrix as dis ussed above is also a bit verbose. Also, if someone uses a ve tor of ve tors in
a program, there is always the suspi ion that they may be hanging the sizes of the rows
as des ribed above. It is easier to understand a program if we are assured that a parti ular
name always refers to a matrix 10  20 matrix, and that some fun tion will not suddenly
hange it to be ome a 5  5 triangular matrix. In other words, we want to signal to the
reader that we are really using only the usual kind of matrix operations, not using all the
ve tor fun tions. For this, we an reate a matrix lass.
20.2.6 A matrix lass
A safe matrix lass is de ned below. It does not allow the size of the individual rows to be
hanged on e reated, and only allows a ess to elements for reading and writing.
lass matrix{
ve tor<ve tor<double> > elements;
publi :
matrix(int m, int n) : elements(m, ve tor<double>(n)){}
double &operator()(int i, int j){return elements[i℄[j℄;}
int nrows(){return elements.size();}
int n ols(){return elements[0℄.size();}
};

It an be used in a main program su h as the following.


Abhiram Ranade, 2013. Do not distribute 338
int main(){
matrix D(10,10); // 10 x 10 matrix

for(int i=0; i<D.nrows(); i++){


for(int j=0; j<D.n ols(); j++)
D(i,j) = (i==j); // a ess i,j th element
}

for(int i=0; i<D.nrows(); i++){


for(int j=0; j<D.n ols(); j++)
out << D(i,j) <<' ';
out << endl;
}
}
As you an see we have overloaded the fun tion all operator to a ess the elements. This
is be ause we need to supply two indi es, and the indexing operator [℄ an only take one
index. Thus the fun tion all operator is more onvenient. Also note that as de ned, the
default assignment operator is available to the lass. You an disable that if you wish by
making it private.
The lass an be templatized so as to form a matrix of arbitrary type T rather than a
matrix of type double.

20.3 Sorting a ve tor


The standard template library ontains many useful fun tions whi h you an a ess by
in luding another header le.
#in lude <algorithm>
If you in lude this le, sorting a ve tor v is easy, you simply write:
sort(v.begin(), v.end());
That's it! This fun tion will sort the ve tor v in-pla e, i.e. the elements in v will be rearranged
so that they appear in non-de reasing order. The arguments to the sort fun tion indi ate
what portion of the array to sort. By writing v.begin() you have indi ated that the portion
to sort starts at the beginning of v, and v.end() indi ates that the portion to sort ends at
the end of the ve tor. In other words, the entire array is to be sorted. The expression
v.begin() evaluates to an iterator. An iterator, whi h we will dis uss in Se tion 20.6, is a
generalization of pointers. The expression v.end() is also an iterator.
The sort fun tion an be used to sort arrays of arbitrary lass. For this we must somehow
spe ify a omparison fun tion, i.e. a fun tion whi h takes two obje ts and says whether the
rst one is smaller than the se ond. If we provide su h a fun tion, then the array an be
sorted in as ending order as per the omparison fun tion. There are 3 ways in whi h the
omparison fun tion an be spe i ed.
Abhiram Ranade, 2013. Do not distribute 339
First, we an de ne the binary operator < for the lass (Se tion 16.4). Thus the sort
fun tion will all the member fun tion operator< to de ide whether one obje t is smaller
than another. We will see an example of this in Se tion 20.4.2.
Se ond, we an de ne an non-member omparison fun tion. This fun tion must be
passed as an additional argument to the sort fun tion. We will see an example of this in
1

Se tion 20.4.3.
Third, we an de ne a fun tion obje t (Se tion 16.4) whi h performs the omparison as
required. This fun tion obje t an then be passed as an additional argument to the sort
fun tion. Se tion 20.4.3 gives an example of this also.

20.4 Examples
We onsider variations of the marks display program of Se tion 13.2.2.
Our rst variation is extremely simple: the tea her enters the marks and the program
must print them out in the sorted order. The main interesting feature here is that the
program is not given the number of marks before hand, and so will need a exible data
stru ture in whi h to store the marks.
20.4.1 Marks display variation 1
We merely read the marks into a ve tor, use the sort fun tion to sort, and nally print.
int main(){
ve tor<float> marks;

int nextVal;
while( in >> nextVal) // read into the ve tor marks
marks.push_ba k(nextVal);

sort(marks.begin(), marks.end()); // sort the ve tor

for(int i=0; i<marks.size(); i++) // output. Note the use of


out << marks[i℄ << endl; // standard array syntax.
}

It is assumed that the marks le is redire ted to the standard input during exe ution.
20.4.2 Marks display variation 2
Suppose now that our marks le ontains lines of the form: roll number of the student
earning the marks, followed by the marks. Again, we are not expli itly given the number of
entries and the goal is to print out the list in a sorted order of the roll numbers.
More a urately, we pass a pointer to the fun tion, as dis ussed in Se tion 11.7. But note that as
1
dis ussed in Se tion 11.7.1, we an drop the & operator while referring to fun tion pointers.
Abhiram Ranade, 2013. Do not distribute 340
The natural way to write this program is to use a stru ture in whi h to read the roll
number and marks. We would then use a ve tor of stru tures. In order to be able to sort
a ve tor of stru tures, we simply de ne a member fun tion operator<, whi h de ide whi h
stru ture is to be onsidered smaller given two stru tures. Sin e we want to order by roll
number, we must onsider the stru ture whi h ontains the smaller number to be the sorter
stru ture. That is what the de nition of operator< does, in the ode below. Note an
important point: the sort fun tion requires that the fun tion operator< be de ned, with
both the re eiver and the argument being onst.
stru t student{
int rollno;
float marks;
bool operator<( onst student& rhs) onst{ // used by the sort fun tion
return rollno < rhs.rollno; // note the two onst keywords
}
};

int main(){
ve tor<student> sve ;

student s;
while( in >> s.rollno){
in >> s.marks;
sve .push_ba k(s);
}

sort(sve .begin(), sve .end()); // will use operator< internally

for(int i=0; i<sve .size(); i++)


out << sve [i℄.rollno << " " << sve [i℄.marks << endl;
}

20.4.3 Marks display variation 3


Suppose now that our input is as in Se tion 20.4.2, however, we want two printouts: one
sorted by roll number, and another by marks. De ning operator< in the student lass will
not suÆ e now, we ould de ne it to sort by roll number, or by marks, but not by both.
So in this ase we rst de ne a omparison fun tion. For example we might de ne:
bool ompareMarksFun tion( onst student &a, onst student &b){
return a.marks < b.marks;
}
We will shortly see how this an be used to sort by marks. Note that we ould have used
a fun tion obje t instead of a fun tion. So for the sake of variety, we will use a fun tion
obje t to sort by roll numbers. So we rst de ne a stru t from whi h to reate the fun tion
obje t.
Abhiram Ranade, 2013. Do not distribute 341
stru t ompareRollnoStru t{
bool operator() ( onst student& a, onst student& b){
return a.rollno < b.rollno;
}
};
Now the main program an be written.
int main(){

// ode to define sve and read into it as before

sort(sve .begin(), sve .end(), ompareMarksFun tion); // by marks

for(unsigned i=0; i<sve .size(); i++)


out << sve [i℄.rollno << " " << sve [i℄.marks << endl;

sort(sve .begin(), sve .end(), ompareRollnoStru t()); // by roll no

for(unsigned i=0; i<sve .size(); i++)


out << sve [i℄.rollno << " " << sve [i℄.marks << endl;
}
In this ode an extra argument has been passed to both alls to sort, spe ifying how the
sorting must happen. The argument in the rst all is really a fun tion pointer, but the
& operator is not written out sin e it an be dropped (Se tion 11.7.1). In the se ond all,
the last argument is ompareRollNoStru t(). This is a all to the onstru tor, so what is
passed is an obje t of the lass ompareRollNoStru t. This is used to de ide the sorting
order.
As you an see, passing a fun tion or a fun tion obje t to sort is more exible than
de ning operator< in the lass { you an sort a ording to di erent orders by passing
di erent fun tions or fun tion obje ts.

20.5 The map template lass


The simplest way to think of the map lass is as a generalization of an array or a ve tor. In
an array or a ve tor, the index is required to be an integer between 0 and the n 1 if the
length of the array is n. In a map, this ondition is severely relaxed: you are allowed to use
any value as the index, it need not even be numeri al! As in an array, the value of the index
determines whi h element of the map is being referred to.
To use the map template lass you need to in lude the header <map>. Next, you de lare
the map you want.
map<indexType,valueType> mapname;
This auses a map named mapname to be reated. It stores elements of type valueType, whi h
an be a essed by supplying indi es of type indexType. It is required that the operator
Abhiram Ranade, 2013. Do not distribute 342
operator< be de ned for the type indexType. Of ourse, if the operator is not originally
de ned, you an de ne it. However the de nition should have the usual properties expe ted
of a omparison operator, i.e. it should be transitive and asymmetri .
Let us take a simple example. Suppose we want to store the population of di erent
ountries. Then we an reate a map named Population, whi h will store the population
value (numeri ). Say we store the population in billions as a unit, so our valueType is
double. We would like to use the name of the ountry to a ess the element orresponding
to ea h ountry, so our indexType ould be string. So we an de ne our map as follows.
map<string,double> Population;
Next we insert the information we want into the map, i.e. we spe ify the population of
di erent ountries.
Population["India"℄ = 1.21; // population of India is 1.21 billion
Population["China"℄ = 1.35;
Population["Unites States"℄ = 0.31;
Population["Indonesia"℄ = 0.24;
Population["Brazil"℄ = 0.19;
The rst line, for example, reates an element whose value is 1.21, and whose index is
"India". You use an array a ess like syntax also to refer to the reated elements. For
example, the following
out << Population["Indonesia"℄ << endl;

will print 0.24, whi h is the value stored in the element whose index is "Indonesia".
You have to realize that while the statements look like array a esses super ially, their
implementation will of ourse be very di erent. E e tively, what gets stored when you write
Population["India"℄ = 1.21; is the pair ("India",1.21). The name Population really
refers to a olle tion of su h pairs. Subsequently, when we write Population["India"℄ we
are e e tively saying: refer to the se ond element of the pair whose rst element is "India".
So some ode will have to exe ute to nd this element (Se tion 20.5.2). So a lot is happening
behind the s enes when you use maps.
What if you write two assignments for the same index, e.g.
Population["India"℄ = 1.21;
Population["India"℄ = 1.22;

This will have the e e t you expe t: the element reated the rst time around will be
modi ed so that the value stored in it will hange from 1.21 to 1.22.
An important operation you might want to perform on a map is to he k if the map
ontains an element with a given index. Suppose you have read in the name of a ountry
into a string variable ountry. Say you want to print out the population of that ountry if
it is present in the map; else you want to print out a message saying that the population of
that ountry is not known to the program. You an write this as follows
Abhiram Ranade, 2013. Do not distribute 343
out << "Give the name of the ountry: ";
string ountry;
in >> ountry;
if (Population. ount( ountry)>0)
out << Population[ ountry℄ << endl;
else out << ountry << " not found.\n";
This ode should immediately follow the ode given above for de ning the map Population
and spe ifying the population of the various ountries.
In this ode the member fun tion ount takes as argument an index value, and re-
turns 1 if an element with that index is present in the given map. Thus suppose the
user typed in "India", in response to our request to give the name of a ountry. Then
Population. ount( ountry) would return 1 be ause we did enter the population of "India"
into the map earlier. So in this ase the nal value entered, 1.22, will get printed. On the
other hand, if the ountry typed in was "Britain", then Population. ount( ountry)
would return 0, and hen e the message \Britain not found." would be printed. Another way
of determining whether a map ontains a ertain entry is dis ussed in Se tion 20.6.1.
You may wonder what would happen if we anyway exe ute
out << Population["Britain"℄ << endl;
without assigning a value to Population["Britain"℄ earlier in the ode. The exe ution of
this statement is somewhat unintuitive. In general suppose we have de ned a map
map<X,Y> m;
and suppose x is a value of type X. Then if we a ess m[x℄ without rst assigning it a
value, then impli itly this rst auses the statement m[x℄=Y(); to be exe uted, i.e. an
element is reated for the index x, and the element stores the value Y() obtained by all-
ing the default onstru tor of lass Y. After that the value of m[x℄ is returned. Thus
in the ase of the statement out << Population["Britain"℄ << endl;, the statement
Population["Britain"℄=double(); is rst exe uted. The onstru tor for the type double
unfortunately does not initialize the value. So the map will now ontain an element of un-
known value but having the index "Britain". Hen e this unknown value would get printed.
20.5.1 Marks display variation 4
In this, we will have the tea her enter the names of the student instead of the roll numbers.
We will onsider the original problem, i.e. students walk up to the omputer and want
to know their marks. But this time they type in their name rather than the roll number.
Clearly, we an use strings to represent student names, and a map to store marks of students.
To make the problem more interesting, we will assume that for ea h student we have the
marks in Mathemati s, Physi s, and Sanskrit. Further assume that the names are given in
a le with lines su h as the following.
A. A. Fair, 85, 95, 80
Vibhavari Shirurkar, 80, 90, 90
Ni olas Bourbaki, 95, 99, 75
Abhiram Ranade, 2013. Do not distribute 344
i.e. the le will ontain a line for ea h student with the name appearing rst, su eeded
by a omma, following whi h 3 numbers would respe tively give the marks in the di erent
subje ts. The numbers are also separated by ommas. This format, in whi h ea h line of the
le ontains values separated by ommas, is often alled the CSV format, or the \ omma
separated values" format.
We will use a string to store the student name. To store the marks, we will use a
stru ture.
stru t marks{
double s ien e, math, sanskrit;
};

The marks will be stored in a map, whose index will be the name of the student given as a
string.
map<string,marks> mark_map;

Say our le ontaining the marks is named marks.txt. Then we an de lare it in our program
as
ifstream infile("marks.txt"); // needs #in lude <fstream>
Next we dis uss how to read values from a le in the CSV format. For this we an use a
form of getline fun tion whi h allows a delimiter hara ter to be given. The signature for
this is:
istream& getline(istream& instream, string stringname, har delim)

In this, instream is the name of the input stream from whi h data is being read. The
parameter stringname is the name of a string, and delim is the hara ter that delimits the
read. Thus, data is read from the stream instream until the hara ter delim is found. The
hara ter delim is dis arded, and the data read till then is stored into string stringname.
Thus, we an read the name of a student by exe uting something like:
string name;
getline(infile,name,',');
Used with the le above, this statement will ause name to get the value \A. A. Fair",
in luding the spa es inside it. Subsequently if we exe ute
getline(infile,name,',');
again, the string name would then hold the string "85". Of ourse, we would like to onvert
this to a double, so we an use a stringstream (Appendix F).
double mmath;
stringstream (name) >> mmath; // need #in lude <sstream>
Abhiram Ranade, 2013. Do not distribute 345
This would ause the string name to be onverted into a stringstream, from whi h we read
into the variable mmath. Similarly, the other data an be read.
Figure 20.1 ontains the entire program based on these ideas. In the rst part, the le is
read into the map mark map. The rst 3 values on ea h line, the name, the marks in math
and the marks in s ien e are omma separated. So they are used as dis ussed above. The
last eld is not omma separated, so it an be read dire tly. Note that when reading using
the operator >>, the end of line hara ter is not read. So before the next line is to be read,
it must be dis arded.
In the se ond part, the program repeatedly reads the names of students. If a name is
present in the map, then the orresponding marks are printed.
20.5.2 Time to a ess a map
The (index,value) pairs onstituting a map are stored using binary sear h trees (Se tion 22.2.1).
As will be dis ussed in Se tion 22.2.7, making an a ess su h as Population[ ountry℄ hap-
pens fairly fast, i.e. in time proportional to log n, where n is the number of ountries for
whi h data is stored in the map.
2

20.6 Containers and Iterators


The lasses ve tor and map are onsidered to be ontainer lasses, i.e. they are used to hold
one or more elements. Even a string is thought of as a ontainer be ause it ontains sets of
hara ters. There are other ontainers as well in the Standard Library, and we will glan e
at some of them shortly.
The standard library allows some generi pro essing of ontainers, be they ve tors, or
maps, or even strings. For this, it is ne essary to be able to refer to the elements of the
ontainer in a uniform manner. This is a omplished using an iterator.
An iterator an be thought of as a generalized pointer to an element in a ontainer.
It is intended to be used in a manner analogous to the use of an (a tual) pointer in the
following ode whi h applies a fun tion f to all the elements of an array.
int A[10℄
int* Aptr
for(Aptr = A; Aptr<A+10; Aptr++) f(*Aptr);

In this ode we initialize the (a tual) pointer Aptr to point to the zeroth element of A, and
then in rement it so that it points to su essive elements. In ea h iteration we dereferen e
it and then apply the fun tion f to it. Impli it in this ode is the idea that the elements are
ordered in a unique manner: spe i ally the elements are onsidered in the order in whi h
they are stored in memory.
Now we see how we an write analogous ode for ontainers. Analogous to the a tual
pointer Aptr, we will have an iterator whi h will abstra tly point to elements of the ontainer,
and whi h we an step through as the exe ution pro eeds. In general, an iterator for a map
an be de ned as follows.
Abhiram Ranade, 2013. Do not distribute 346

#in lude <simple pp>


#in lude <fstream>
#in lude <sstream>
#in lude <map>

stru t marks{
double s ien e, math, sanskrit;
};

int main(){
ifstream infile("students.txt");
map<string,marks> mark_map;

marks m;
string name;

while(getline(infile,name,',')){
string s;
getline(infile,s,',');
stringstream (s) >> m.math;
getline(infile,s,',');
stringstream (s) >> m.s ien e;
infile >> m.sanskrit; // read dire tly, not omma terminated
getline(infile,s); // dis ard the end of the line hara ter

mark_map[name℄ = m; // store the stru ture into the map


}

while(getline( in,name)){
if(mark_map. ount(name)>0)
out << mark_map[name℄.math << " " << mark_map[name℄.s ien e
<< " " << mark_map[name℄.sanskrit << endl;
else
out << "Invalid name.\n";
}
}

Figure 20.1: Program for Marks display variation 4


Abhiram Ranade, 2013. Do not distribute 347
map<X,Y> m;
map<X,Y>::iterator mi;
Here mi is the iterator, and its type is map<X,Y>::iterator. Next we need to say how
to set it to \point" to the rst element in the map, and then how to step it through the
elements. For this we rst need to x an ordering of the elements stored in the ontainer.
For ve tors and maps, the elements are onsidered ordered a ording to the index, i.e. the
rst element is the element with the smallest index. The member fun tion begin on the
ontainer returns an iterator value that abstra tly point to this rst element. Thus we an
initialize our iterator by writing:
mi = m.begin();
An iterator supports two operations: by dereferen ing you get to the element abstra tly
pointed to by the iterator, and by using the operator ++, the iterator an be made to point
to the next element in the order. Finally, to determine when the iterations should stop we
need to know when the iterator has been in remented beyond the last element in the order.
For this the member fun tion end on the ontainer is de ned to abstra tly point beyond the
last element, just as the address A+10 in the example above points beyond the last element
of the array.
Suppose we wish to merely print all the elements in a ontainer. Then here is how this
an be done using iterators, rst for the ontainer marks of Se tion 20.4.1.
for(ve tor<float>::iterator mi = marks.begin();
mi != marks.end();
++mi)
out << *mi << endl;
The ode for map ontainers is similar. When we dereferen e a map iterator, we get an
element of the map, whi h is an (index,value) pair. The pair that we get is a (template)
stru t, with data members first and se ond whi h hold the index and the value respe -
tively. Sin e we onsider an iterator to be a pointer, the stru t elements an be a essed
using the operator ->. Here is how we an print out the map Population of Se tion 20.5.
for(map<string,double>::iterator Pi = Population.begin();
Pi != Population.end();
++Pi)
out << Pi->first <<": " << Pi->se ond << endl;
Similar ode an be written for the string lass. Note that the dereferen ing operator *
or the in rementation ++ should not be understood literally, these operators are given to
you appropriately overloaded. But you dont need to worry about all this; you an onsider
iterators to be abstra tions of pointers for the purpose of using them.
20.6.1 Finding and deleting map elements
Iterators are spe ially important for the map lass. We an use the find operation on iterators
to get to an (abstra t) pointer to an element whi h has a given index value. Thus to see if
the value "Britain" is stored in the map Population, we an write:
Abhiram Ranade, 2013. Do not distribute 348
map<string,int>::iterator Pi = Population.find("Britain");
If "Britain" is not present, then Pi would take the value Population.end(). So to see if
"Britain" is present and print its population we an write:
map<string,int>::iterator Pi = Population.find("Britain");
if(Pi != Population.end())
out << Pi->first << " has population "<<Pi->se ond << endl;
You an delete the element pointed to by an iterator by using the erase fun tion as follows.
map<string,double>::iterator Pi = Population.find("Indonesia");
Population.erase(Pi);
This would remove the entry for Indonesia.
20.6.2 Inserting and deleting ve tor elements
Iterators an be used with ve tors for inserting and deleting elements. For example, we ould
write
ve tor<int> v;
for(int i=0; i<10; i++) v.push_ba k(i*10);

ve tor<int>::iterator vi = v.begin()+7;
v.insert(vi,100); // inserting into a ve tor

vi = v.begin() + 5;
v.erase(vi); // deleting an element

The rst two statements respe tively de lare a ve tor v and set it to ontain the elements
0, 10, 20, 30, 40, 50, 60, 70, 80, 90. The third statement auses vi to point to the seventh
element of v, i.e. the element ontaining 70. Then 100 is inserted at that position, the
elements in the positions seventh onwards being moved down one position. The size of the
ve tor of ourse in reases by one. After that we set vi to point to the fth element. Then
that element is deleted. This auses the subsequent elements to be moved up one position.
Thus at the end the ve tor v would ontain the elements 0, 10, 20, 30, 40, 60, 100, 70, 80,
90.

20.7 Other ontainers in the standard library


The standard library has several other ontainers whi h are very useful.
For example, the ontainer deque is a double ended queue, into whi h you may insert or
remove elements from the front as well as the ba k. The ontainer queue allows insertions
at the ba k and removal from the front, while the ontainer sta k requires that insertions
and removals both be done from the same end.
Abhiram Ranade, 2013. Do not distribute 349
An important ontainer is the priority queue. You an insert elements arbitrarily, how-
ever, when removing elements, you always get the smallest element inserted till then. We
dis uss and use priority queues in Chapter 25.
An interesting ontainer is the set. This supports operations for inserting elements and
subsequently nding them. The elements are required to have operator< de ned on them,
and this order is used for storing the elements in a binary sear h tree, just as a map was
stored in a binary sear h tree. The elements are ordered a ording to the operator< order
de ned on them, and will get printed in this order if printed using iterators as in Se tion 20.6.
So if we store elements in a set, we really dont need to expli itly sort them.
This des ription is of ourse very sket hy. You should onsult various standard library
referen es on the web to get details.

20.8 The typedef statement


The typedef statement an be used to reate a new name for an existing type.
typedef existingType newName;
So for example, you an write
typedef map<string,double> popType;
typedef ve tor<ve tor<double> > matrix;
So with these de nitions, you an write popType and matrix instead of the longer names,
and save yourself typing and perhaps make your programs more readable.
Of ourse, the typedef statement is not in any way limited to being used with ontainer
types from the standard library. It an be used also for ordinary types.
typedef double mynum;
With this, you ould use mynum as a synonym for double. This is useful in ase you de ide
one day that you really want to represent the numbers in your program using long double.
If you had de lared them to be of type mynum, then you would only need to make the hange
in the de nition of mynum, rather than hange the de nition of every numeri al variable in
your program.
20.8.1 More general form
The above type de nitions ould be onsidered to be only onvenient, but not providing new
apability. This is be ause you ould textually substitute existingType for newTypename.
However, there is a general form whi h a tually provides new apability. The form is:
typedef existingType newTypeExpression;
This de nes an equivalen e between existingType and newTypeExpression. Here is an
example.
typedef double (*fptrtype)(double,int);
Abhiram Ranade, 2013. Do not distribute 350
This says that double is the same as the type you get when you dereferen e something of
type fptrtype, and then apply that to arguments of type double and int. In other words,
fptrtype is of type pointer to fun tion that takes a double and int as argument and returns
a double. As you an see, there is no other way to de ne the type fptrtype. With this
de nition of fptrtype, you ould de ne ph from the end of Se tion 11.7 as follows.
fptrtype ph;

20.9 Remarks
You have probably guessed by now that the lasses we dis ussed in this hapter would have
to be implemented in the style of the String lass dis ussed in Chapter 19. Indeed that is
true. They will use heap memory to store data, and allo ate and deallo ate heap memory
when needed.
The important point to note however is that you dont have to worry about the implemen-
tation in order to use these lasses. Indeed the onstru tors, destru tors, opy onstru tors,
assignment operators of these lasses have already been written, so that there are no memory
leaks, dangling pointers et . You dont need to worry about memory allo ation; indeed you
should be able to do everything you want without ever having to use the new operator.

20.10 Exer ises


1. Explain what ea h statement of the following ode fragment does.
ve tor<int> a(5,33);
ve tor< har*> ountries(4);
ve tor<ve tor<double> > v(3,ve tor<double>(5, 3.14));

2. Write a ode fragment that reates a 10  10 matrix stored as ve tor of ve tors of


doubles and initializes it to the identity matrix.
3. Write a program to multiply two matri es of arbitrary sizes represented as ve tor of
ve tors.
4. Write a fun tion whi h returns a lower triangular matrix using a ve tor of ve tors.
Spe i ally, you should only allo ate spa e to store elements aij where j  i.
5. De ne a lass LTM for storing lower triangular matri es, with signature as follows.
lass LTM{
ve tor<ve tor<double> > data;
publi :
LTM(int n);
double getElem(int i, int j);
void setElem(int i, int j, double v);
}
Abhiram Ranade, 2013. Do not distribute 351
As you might guess the onstru tor onstru ts an LTM matrix with the given number
of rows and olumns. The member fun tions return the element at index i,j and
assign the value v to the element at index i,j respe tively. Note that if j>i then
getElem must return 0. If j>i the setElem must do nothing and print a message.
Give implementations of all the member fun tions. Of ourse, it will be mu h ni er to
use array indi es rather than getElem and setElem. The natural indexing operator is
[℄ { but that an take only one index. So instead overload the () operator, so that
the fun tion arguments an be indi es. Return a referen e so that you an use assign
to array elements as well as read array elements.
6. Write a program that will re eive information about the states of India and their
apitals and answer questions about these when asked. Spe i ally it should pro ess
3 kinds of ommands. The rst kind is:
Learn state apital

As an example, the user may type Learn Maharashtra Mumbai. In this ase this
information must be remembered by the program. The se ond kind of ommand is
Tell apital-or-state-name

For example, the user may type Tell Gandhinagar, whereupon the program must
respond that it is the apital of Gujarat. Likewise if the state is given its apital must
be given in response. The third kind of ommand is just
Exit

whereupon the program must exit.


7. Write a program that prints out all positions of the o urren es of one string pattern
inside another string text. Use appropriate fun tions from the string lass.
8. Design a lass to eÆ iently store sparse polynomials i.e. polynomials in whi h even if
the degree is n, there may be far fewer terms in the polynomial, i.e. many of the powers
might have oeÆ ient 0. In su h ase, it may be wasteful to allo ate an array or ve tor
of size n + 1 to store a polynomial. Instead, it might be more eÆ ient to store only
the non-zero oeÆ ients, i.e. store the pair (i; ai) if the oeÆ ient ai of xi is non-zero.
Use a map to store su h pairs. Write fun tions to add and multiply polynomials. Note
that iterators on maps will go through stored pairs in lexi ographi al order. Exploit
this order to get eÆ ient implementations.
9. Suppose for ea h student we know the marks in several subje ts. The total number of
subje ts might be very large, of whi h ea h student might have studied and got marks
in some. Write a program whi h reads in the marks a student has obtained in di erent
subje ts, and then prints out the marks obtained given the name of a student and the
name of the subje t for whi h the marks are requested.
You are expe ted to use a map to store the data for all students, and a map for ea h
student in whi h to store the marks for the di erent subje ts taken by the student.
Abhiram Ranade, 2013. Do not distribute 352
10. The algorithm olle tion in standard library also ontains a binary sear h fun tion
for performing binary sear h on sorted ontainers su h as ve tors. The signature of
this fun tion is
bool binary_sear h(ForwardIterator first, forwardIterator last,
onst T& value_to_sear h);

Here the region of the ontainer between first (in lusive) and last (ex lusive) is
sear hed to nd an element equal to value to sear h. The type of the element stored
in the ontainer must be T. An additional argument, a fun tion obje t is also allowed.
The fun tion obje t must implement the < operator for obje ts of type T (Se tion 20.3).
Use this to implement variation 4 of the marks display program, using just ve tors
rather than maps.
The fun tion binary sear h is guaranteed to exe ute in logarithmi time when used
with ve tor ontainers.
11. Write a program whi h implements a di tionary of the English language. A natural
representation would be a map, with the words being the indi es and the meanings
being the values. This will be suitable for exa t look ups. However, suppose we wish
to nd approximate mat hes too. This is be ause we will typi ally only store the root
words in the di tionary, e.g. the word \di tionary", but not the words obtained from
the root by in e tion, e.g. the word \di tionaries". In su h ases, when you look up
\di tionaries", you would like to get the word that has the longest pre x mat h, whi h
will likely be \di tionary" in this ase. After that your program ould de ide whether
the word you found an indeed be in e ted to give the word you are looking for. For
su h pro essing, perhaps a simple (sorted) ve tor might be a better representation than
a map. In any ase, write a program whi h not only tells you whether the given word is
in the di tionary, but also whether it is likely an in e tion of a word in the di tionary.
Chapter 21

Representing networks of entities

Many real life systems an be onsidered to be olle tions of entities whi h are somehow
linked together into a network. For example, a ir uit onsists of omponents onne ted
together by wires. Roads onne t ities. When you browse the internet, you an go from
one page to another by li king on a link, a link in the page thus onne ts the page to other
pages. Or the entities might be people, with individuals linked to one another if they are
friends. This hapter will be an introdu tion to omputations relating to su h networks,
whi h we will loosely de ne as olle tions of entities along with the onne tions between
them.
There may be several questions we ould ask about su h networks. For a ir uit, we
might want to know the urrents and voltages in the di erent omponents. In a road map
we might want to know the shortest path to go from one ity to another. We might want
to determine the importan e of ea h page on the internet. Sea h engines have to routinely
answer this question when they have to show results of a web sear h { the more important
pages must be listed before the less important ones. In a network of friends, you might
perhaps want to know who has the largest number of friends, or whether two individuals
have a mutual friend. Some su h questions require substantial mathemati al and omputer
s ien e ideas whi h are outside the s ope of this book.
However, it is possible to get some sense of how to represent su h networks on a omputer,
and answer at least some simple questions about them. That is what we hope to a omplish
in this hapter. Our dis ussion will be based on examples, but it is hoped that you will get
some understanding of how to represent networks in general and perhaps do some elementary
pro essing with them.
The basi mathemati al model used to represent networks is a graph. We begin by
dis ussing the ommon representations used for representing graphs. We then dis uss spe i
networks and operations on them. In Chapter 22 we will see additional examples of linked
stru tures, and how they an be pro essed.

21.1 Graphs
A graph, as you might know, onsists of two sets, V , a set of verti es, and E , a set of edges.
Ea h edge is a pair (u; v), where u; v 2 E . An edge (u; v) is said to onne t the verti es u; v.
The edges may be dire ted or undire ted, orrespondingly, we may onsider the pairs (u; v)
353
Abhiram Ranade, 2013. Do not distribute 354
to be ordered or unordered. It is also ustomary to say that an edge (u; v) is in ident on
verti es u; v. It is also ommon to use the term node instead of the term vertex.
As you might guess, verti es orrespond to the entities in our network, and edges to the
onne tions between them. Verti es and edges may be asso iated with additional attributes,
e.g. the verti es may have names orresponding to the names of entities, edges may have
weights, re e ting say, the strength of the onne tion between the entities. Undire ted edges
are used to represent symmetri relationships, e.g. friendship. Dire ted edges represent
asymmetri relationships, e.g. X is a follower of Y.
Most ommonly, verti es are represented by obje ts in C++. Often, a network ontains
entities of only a single type, in whi h ase the orresponding verti es will be represented by
obje ts of a single lass. But it is possible to have di erent types of entities. For example
you may have a network in whi h the entities are authors and books, with links between
books and their authors. For this, you will have verti es of lass author and also verti es of
lass book in your graph.
Edges may also be represented by obje ts, or they may be represented more simply.
21.1.1 Adja en y lists
In the simplest ase, edges are represented using a pointers. Thus if there is a dire ted edge
from a vertex u to a vertex v, the obje t orresponding to u will ontain a pointer to the
obje t orresponding to the obje t orresponding to v. If an edge (u; v) is undire ted, then
we will have a pointer to v in obje t u, as well as a pointer to u in obje t v. In general, ea h
vertex will have many edges. In this ase the asso iated pointers will be stored in a list,
hen e the name adja en y list. In C++, it is most natural to use ve tors to build lists.
As an example, we how a network of friends may be represented.
stru t Person{
string name;
ve tor<Person*> friends;
};
The entities/verti es will be obje ts of lass Person. We an reate persons by writing:
Person persons[5℄;

Their names an be lled in as follows.


persons[0℄.name = "Harry";
persons[1℄.name = "Hermione";
persons[2℄.name = "Ron";
persons[3℄.name = "Dra o";
persons[4℄.name = "Crabbe";
Now to make Harry and Hermione friends of ea h other, we merely have to add an undire ted
edge. As we have said, an undire ted edge orresponds to pointers between the orresponding
entities. Thus we must add a pointer to persons[1℄ in persons[0℄.friends, and vi e versa.
For this we will write a fun tion.
Abhiram Ranade, 2013. Do not distribute 355
void makefriends(Person &p, Person &q){ // add an undire ted edge in the graph
p.friends.push_ba k(&q);
q.friends.push_ba k(&p);
}
This an be alled to add the required friendship edge, and others too.
makefriends(persons[0℄, persons[1℄);
makefriends(persons[2℄, persons[1℄);
makefriends(persons[0℄, persons[2℄);
makefriends(persons[3℄, persons[4℄);
Now if we want to print the friends of Hermione (stored in persons[1℄), we merely write:
for(unsigned i=0; i<persons[1℄.friends.size(); i++)
out << persons[1℄.friends[i℄->name << endl;

21.1.2 Extensions
Ea h person need not have links only to his/her friends. Suppose we also want to have
links to enemies. In that ase we merely add another data member enemies of type
ve tor<Person*> to the Person lass. Suppose that some of the persons have a favourite
friend. Representing this is even simpler. Sin e we know that there is at most one favourite,
we just add a data member favourite of type Person*. Thus our de nition now be omes:
stru t Person{
string name;
ve tor<Person*> friends, enemies;
Person* favourite;
}

Given our pre eding de nitions, we an make Ron be Harry's favourite friend by writing
persons[0℄.favourite = &persons[2℄;
On the other hand, if we wanted to indi ate that Harry has no favourite we write
persons[0℄.favourite = NULL:
As you might remember, NULL is a spe ial value, whi h indi ates that no real pointer is
intended.
21.1.3 Array indi es rather than pointers
If we know that all the entities in our network will belong to a single array, e.g. the array
persons as above, then an alternate representation is possible. Instead of storing a pointer
to an obje t, we an store the index of the obje t in the array. Thus our de nition of person
would hange as:
Abhiram Ranade, 2013. Do not distribute 356
stru t Person{
string name;
ve tor<int> friends;
};
Adding an edge between Harry and Hermione would have to be done as:
persons[0℄.friends.push_ba k(1); persons[1℄.friends.push_ba k(0);
And the names of friends of persons[1℄ ould be printed as
for(unsigned i=0; i<persons[1℄.friends.size(); i++)
out << persons[persons[1℄.friends[i℄℄.name << endl;
You may re all that we have used a similar idea in Se tion ??.
21.1.4 Edges represented expli itly
Suppose we wish to represent the network of roads between ities in a ountry.. The ities will
be the verti es in this network, and the roads themselves will be the edges. Sin e inter ity
roads are typi ally two way, we will use two edges for ea h road, one in ea h dire tion. We
ould make roads be pointers from one interse tion to another; but we might also want to
store the names of roads, and their lengths. So it is onvenient to have obje ts to represent
roads too.
A lass for representing interse tions ould be de nes as follows.
stru t Road; // forward de laration so that we an write Road* below.
stru t City{
ve tor<Road*> roads;
}
A road obje t must store the interse tion it leads to; optionally also the interse tion it starts
from, and say its name and length.
stru t Road{
string name;
City* from, to;
double length;
}

We will see this idea developed in Se tion 25.4.

21.2 Adja en y matrix representation


Graphs an also be represented using a so alled adja en y matrix. If the graph has n
verti es, an n  n matrix A is used, with entry Aij giving information about the edge from
vertex i to vertex j , if any. For example, we might set Aij = 1 to indi ate that an edge
Abhiram Ranade, 2013. Do not distribute 357
is present, and Aij = 0 to indi ate that there is no edge. Other values an also be used,
depending upon the ontext, as we will see later.
The main drawba k of the adja en y matrix representation is the large memory required.
An adja en y matrix has n elements, and thus memory for them will be needed no matter
2

how many a tual edges there are. If we use an adja en y list representation, then in ea h
vertex obje t we will use just the memory needed to represent the edges in ident on that
vertex. Thus the total memory used for edge representation is proportional to the number
of edges. If a graph has only a few edges, then the adja en y list representation saves on
memory.
However, there are advantages too for adja en y matri es. The most obvious advantage
is that we an very easily he k whether an edge from vertex i to vertex j exists: we simply
examine the value of Aij . Also, as we will see shortly, in many appli ations, the adja en y
matrix an be dire tly used in operations su h as matrix multipli ation, solving a system of
equations, and so on. So in su h appli ations, the adja en y matrix representation is very
onvenient.
In the exer ises, you are asked to develop a sparse matrix representation: a lass that
behaves like a matrix but uses a smaller amount of storage. With this you an sometimes
get the best of both worlds.
In the following se tions we will see examples of the adja en y matrix representation.

21.3 Sur ng on the internet


We onsider the following s enario. Suppose I start sur ng the net from a ertain webpage.
After a little while, I get bored and I li k one of the links on that page; say I hoose the
link at random. Then I go to that page and read it for some random amount of time. Then
I again li k a random link on that page. I ontinue in this manner. The question is, after
a long enough time has passed, what is the probability that I am reading a ertain page on
the net?
This question might seem rather ontrived or even improperly posed, but it turns out to
be of great importan e! This is be ause of several reasons. First, although web browsing
does not happen entirely in a random manner, it turns out that the random model des ribed
above is a good approximation for how a tual web browsing happens. Se ond, it turns out
that under reasonable onditions (say if it is possible to go from any page to any page by
li king possibly several times), the probability of being at a ertain page after n li ks does
tend to a xed value, as n tends to in nity. Thus with this interpretation, the problem of
nding the probability is indeed well de ned. And the third and the most important reason
is:
Page rank: The probability of being at a given page is an indi ation of the
importan e/"rank" of that page.
This is a rather deep observation, attributed to the founders of the sear h engine Google.
An informal justi ation is: if the probability of being at a page is high, then presumably it
has many in oming links, and perhaps it has many links be ause many people onsider it to
Abhiram Ranade, 2013. Do not distribute 358
be important. As mentioned earlier, when showing the results of a sear h, it is onsidered
1

appropriate to show the important pages rst, and hen e estimating the importan e of a
page is of great value to sear h engine ompanies.
It is most natural to use an adja en y matrix T , often alled the transition matrix, to
represent the network of pages. The basi operation in the al ulation of the page ranks will
be the multipli ation of this matrix using a suitable ve tor. We will soon des ribe the exa t
ontent of T , but before that we need to make our sur ng model a bit more pre ise.
Suppose at some time t the surfer is at some page p. It is ustomary to assume that
time is divided into steps. At ea h step, the surfer de ides whether he/she wants to ontinue
with that page or li k a link and go to some other page. It is ustomary to assume that
with probability 0.5 the surfer will stay on the same page at time t + 1 as he is on at time t.
With probability 0.5 the surfer will li k on one of the links in the page, with the link being
hosen at random. Thus if dp denotes the number of outgoing links from the page, then the
probability that the surfer uses a spe i link to leave the page is 0:5=dp. The matrix is
onstru ted so that Tij will denote the probability that a surfer at page i in step t goes to
page j in step t + 1. Clearly we have:
Tii = 0:5 (21.1)
Tij = 0:5=di if there is a link from page i to page j . (21.2)
Tij = 0 if there are is no link from page i to page j . (21.3)
Thus for the set of pages and the links between them as shown in Figure 21.1, the transition
matrix will be: 0
0:5 0:5 0 0 0 1
B 0 0:5 0:25 0:25 0 C
B C
T = B 0:17 0 0:5 0:17 0:17 C
B
C
 0:5 0 0 0:5 0 A
0:5 0 0 0 0:5
As an example, from page 2 we have 3 outgoing links, to pages 0, 3, and 4. Thus we have
T = T = T = 0:5=3  1:7. And sin e there is no link to page 1 we have T = 0, and of
20 23 24 21
ourse T = 0:5.
22
Suppose we are given the (row) ve tor x where xi denotes the probability of the surfer
being at page i at a ertain step t. From page i the surfer moves to page j with probability
Tij . Thus the probability that at time t the surfer is at page i and that at time t + 1 the
surfer is at page j is xi Tij . Thus to nd the probability yj of the surfer being at page j at
time t + 1 we merely need to add the terms xiTij over all hoi es of i. Thus we have
X
yj = xi Tij
i

In other words, if y denotes the ve tor with entries yj , then we have


y = xT
The probability of being at a page an be high even if a page has few in oming links, if those in oming
1 p

links ome from pages whi h themselves have a large number of in oming links. We an view this
q; r; : : :

situation as: are primarily important be ause there are many in oming links, but is se ondarily
q; r; : : : p

important be ause it has in oming links from important pages! This is the intuition for onsidering the
probability as being indi ative of the importan e.
Abhiram Ranade, 2013. Do not distribute 359

4
1

Figure 21.1: Pages with links

In other words, to get the probabilities for the next step, we need to multiply the probability
ve tor for the urrent step by the transition matrix T . Thus the probabilities at t; t + 1; t +
2; : : : are simply
x; xT; xT 2 ; xT 3 ; : : :
We have already seen the ode for multiplying a matrix by a olumn ve tor; the ode for
multiplying a row ve tor by a matrix is very similar. This is all that is needed!
So suppose now that we are at page 0. This orresponds to x being the ve tor (1; 0; 0; 0; 0).
We an use the above method to nd the probabilities of visiting di erent pages as the time
in reases. Indeed, if you ompute xT , we get
10

x  (0:3; 0:3; 0:15; 0:225; 0:025)


You will see that the ve tor does not hange mu h with subsequent multipli ations. Thus
from this al ulation it would seem that pages 0,1 are most important, and page 4 the least.

21.4 Cir uits


We will onsider the problem of nding the urrents and voltages at di erent points in a
ir uit onsisting of resistors and urrent sour es, su h as the one shown in Figure 21.2. You
may perhaps not be familiar with urrent sour es, the spe i ed urrent ows out of them no
matter what they onne t to. Cir uits whi h ontain voltage sour es an also be analyzed,
but the algebra is slightly more ompli ated. We will dis uss this later.
First we view this ir uit as a graph, i.e. identify the verti es and edges in it. The
resistan es and the urrent sour e an be onsidered to be the edges, the points at whi h
these atta h to ea h other an be onsidered to be the verti es. There are 6 nodes in
Figure 21.2, numbered 0 to 5, shown as solid ir les. There are 9 edges, one onsisting of the
voltage sour e, and 8 onsisting of resistors. It is possible to have ir uits in whi h there are
devi es whi h have more than two ele tri al onne tions to them, su h as transistors. The
model for su h graphs will be di erent.
Abhiram Ranade, 2013. Do not distribute 360
1 4 ohm
2

3 Ohm
2 Ohm

! Ampere

3 4
5 Ohm
6 Ohm

7 Ohm 8 Ohm

3 Ohm

Figure 21.2: Cir uit to be analyzed

It ould be said that the graph of a ir uit is ommonly represented by its adja en y
matrix, the so alled ondu tan e matrix whi h we will denote by G. The entries of the
matrix are lled in a spe ial way, so as to help in analysing the ir uit. Spe i ally we will
have
1. Gij = 1=Rij : if Rij is the value of the resistan e onne ting verti es i and j , where
i 6= j . Note that if no resistor is shown between verti es i; j then we onsider the
resistan e between them to be 1, in whi h ase Gij = 0. You may know that a
resistan e of value R is the same as a ondu tan e of value 1=R. Thus Gij an be
onsidered to be the negative of the ondu tan e onne ted between nodes i; j .
2. Gii = Pj 1=Rij : The value of Gii is thus set to be the sum of the ondu tan es
onne ted to vertex i.
Note that the urrent sour e values does not gure in setting the values of the ondu tan e
matrix.
You an see that the ondu tan e matrix an roughly be onsidered to be an adja en y
matrix for the ir uit: the entries are 0 when there is no onne tion, and the entries are
large (though negative) when there is a high ondu tan e between two verti es. But the real
motivation in setting the entries in this manner is that it helps in ir uit analysis.
For analysis, it is ustomary to asso iate voltages with the di erent nodes, so we de ne
Vi as denoting the voltage at node i. The goal of the analysis is to solve for the variables
Vi where i 6= 0. Considering Vi to be the elements of a ve tor V we an write down the
following equation.
GV = S
Here S is a olumn ve tor also having n elements, and Si denotes the sum of the urrent
leaving vertex i through the urrent sour es atta hed to vertex i. For our ir uit, the equation
Abhiram Ranade, 2013. Do not distribute 361
with the matrix and ve tors shown in full be omes
0 10 1 0
1
+ 1 1
0 0 0 V 1 1 1
0
+ 0 0 0 C CB V C B 1 C
5 3 5 3
B 1 1 1 1 B C B C
B 1
B 0 + + 0 CB V C = B 0 C
5 5 4 4
1 1 1 1 C B1 C B 1
B C 2
B 0 0 + + CB V C B 0 C
4 4 2 3 2 3
1 1 1 1 1 1
B CB C B C 3
 0 0 + + A V A  0 A
2 2 6 7 6 7
1 1 1 1 1 1
4
0 0 + + 0
3 6 3 6 8 8
1
3
1
7
V 1
8
1
3
1
7
1
8 5

Note that in our example, S = 1 be ause unit urrent must ow out of vertex 0 into the
0
urrent sour e. Similarly, S = 1 be ause unit urrent must ow in to vertex 1 from the
1
urrent sour e. There are no urrent sour es asso iated with the other verti es, and hen e
the orresponding Si are 0. Let us rst write down the equation for our ir uit, after that
we will explain why the equation is orre t.
A matrix equation really onsists of as many ordinary equations as there are rows. So
for example, onsidering the rst row of the produ t we will get:
V (1=5 + 1=3) + V ( 1=5) + V ( 1=3) = 1
0 1 5

This equation really turns out to be saying that the total urrent entering vertex 0, through
voltage sour es and resistors, must equal 0, sin e harge annot be reated nor destroyed.
This an be seen if we rewrite the equation a bit.
(V V )  1=5 + (V V )  1=3 + 1 = 0
0 1 0 5

In this you an see the rst term (V V )  1=5 as the urrent entering vertex 0 through the
0 1
5 Ohm resistan e, (V V )  1=3 as the urrent entering through the 3 Ohm resistan e, and
0 5
1 as the urrent entering through the urrent sour e. Indeed you will see the ith row of the
matrix equation to simply be asserting that the total urrent leaving and entering vertex i
must be 0. Thus the matrix equation is valid.
Thus, analysis of this ir uit is merely solving this set of equations! And we know how to
do it from Se tion 14.2.1! There is one slight twist. You may know that voltages in a ir uit
are relative, i.e. we an arbitrarily designate one of the voltages to be 0. For example, we
an substitute V into the matrix. We will now get n equations but only n 1 unknowns!
0
However, this is not a problem: one of the equations is super uous, it does not ontain new
information, and an indeed be obtained by adding the remaining equations! Thus, we an
remove one of the equations too. Typi ally we remove the equation for the same node for
whi h we set the voltage value to 0. This is equivalent to removing row 0 from the matrix and
from both ve tors, and also olumn 0 of the matrix. Thus we will get a system of equations
in n 1 variables whi h we an solve as per Se tion 14.2.1.
We an ompute the urrents in the di erent resistors by multiplying by the voltage drop
a ross the resistan e. Thus the urrent through the 4 Ohm resistan e in the dire tion vertex
1 to vertex 2 is (V V )  1=4, whi h an be al ulated given values of V ; V .
2 1 1 2
We nally onsider how to deal with voltage sour es. Suppose we have a voltage sour e
onne ting verti es i; j . Then we will need to have an additional variable Iij to represent the
urrent through that voltage sour e. But we will also have an equation, viz. Vi Vj must
equal the spe i ed voltage sour e value. Thus again we will have as many equations as there
are unknowns, and we an solve the system.
Abhiram Ranade, 2013. Do not distribute 362
21.5 Edge list representation
21.6 Auxiliary data stru tures
Often it might be useful to maintain additional data stru tures when representing networks.
For example, we may wish to qui kly nd out the obje t that represents a given person,
given the name of the person. A natural way to do this is using a map, from names to the
obje ts representing the person.

21.7 Remarks
We have sket hed some ways of representing networks. However, there an be others. Es-
pe ially if the network has some spe ial stru ture, then we may be able to assign numbers
to di erent verti es su h that from the number of a node it is lear what other nodes are
onne ted to it. We will see an example of this in Chapter 26, where we will suitably number
the runways and taxiways so that it is lear from the numbers what other runways/taxiways
a given runway onne ts to.
We should also note that in this hapter, we have de ned all lasses as stru ts, i.e. so
that every member is publi by default. That was only for keeping the ode short. In a tual
programming, you should follow the usual rule that data members should be private and
a sele ted fun tion members publi . Indeed, this is what you should do when solving the
Exer ises.

21.8 Exer ises


1. Write a program that onstru ts representations about friendship and enemity as dis-
ussed in Se tion 21.1.1. It should take as input a le ontaining information about
how many persons are there, who are the friends of ea h person, who are their enemies,
and who are the favourite friends of ea h person if any.
Write fun tions to (a) Find whether two given persons have ommon friends, (b) Find
the the most popular person, i.e. the person who is named as the favourite by the
largest number of persons.
2. Code up the page rank al ulation and he k if the nal probabilities indeed tend to
the same limit, no matter what initial node you start from.
3. We have noted that many in many natural matri es, e.g. a transition matrix or a
ondu tan e matrix, many elements are 0. To save memory, it is desirable to have a
representation in whi h we only store the non-zero elements. Of ourse, the represen-
tation should be apable of listing out all elements of the matrix if needed (whether
they are zero or non-zero), but it should not expli itly store the elements with value 0.
Instead, if an element is not expli itly stored, it should be onsidered to be 0. Devi e
su h a representation. Hint: It will e e tively be the adja en y list representation of
the matrix.
Abhiram Ranade, 2013. Do not distribute 363
Write a member fun tion for the lass so that you an perform matrix ve tor multipli-
ation using that matrix.
4. Suppose in Figure 21.2 we have a voltage sour e of value 1 volt, between verti es 3 and
4 (with vertex 3 onne ted to the positive end of the voltage sour e). Add the relevant
equation into your program and nd the resulting urrents.
In general extend your program to handle voltage sour es.
5. Devise graphi al editors to input ea h of the networks dis ussed in this hapter. For
example to reate a friendship network, your editor will have a button to reate a
person. Then additional buttons to reate friendship links and so on. The editors
should also have buttons whi h when li ked will suitably pro ess the given network.
Where relevant, devi e ways to show the result also on the graphi s anvas.
Chapter 22

Stru tural re ursion

Consider the following mathemati al formulae:


=
4
1+ 1 2

3+ 2 2

5+ 3 2

7+ 4.
2

9 + ..
and n
X n(n + 1)(2n + 1)
i2 =
i=1
6
Both are orre t, and the rst one is rather elegant. Our on ern in this hapter, however, is
not the validity or elegan e of these formulae. Our on ern is mu h more mundane: how do
we layout these formulae on paper. Where do we pla e the numerator and the denominator,
how long do we make the lines denoting division? What if the denominator is itself a
ompli ated expression as was the ase in the ontinued fra tion expansion for ? Can we
have a omputer program do all these al ulations for us? While this is somewhat tri ky,
many programs are indeed available for doing this, the most important amongst these is
perhaps the TEX program developed by Donald Knuth. The program TEX has a language
for spe ifying mathemati al formulae, and in this language, the two formulae above an be
spe i ed as:
\pi = \ fra {4}{1+\ fra {1^2}{3+\ fra {2^2}{5+\ fra {3^2}
{7+\ fra {4^2} {9+\ddots}}}}}
and
\sum_{i=1}^ni^2=\fra {n(n+1)(2n+1)}{6}
Given this textual des ription, TEX an generate layouts like the ones shown. While the
textual des ription is quite rypti , you an probably make some sense of it. You an guess,
perhaps, that the symbol ^ is used by TEXto denote exponentiation. Or that nfra and
364
Abhiram Ranade, 2013. Do not distribute 365
Desired output Input required by our program
a
1. b+
(a/(b+ ))

b
2. a+

(a+(b/ ))

3. a+b+ +d (((a+b)+ )+d)

x+1 x
4. + +6
x+3 5
((((x+1)/(x+3))+(x/5))+6)

Figure 22.1: Examples of output and input


n fra somehow denote fra tions. Even without pre isely understanding the language of
TEX you an see that the spe i ation does not ontain any geometri information. The
spe i ation does not say, for example, how long the lines in the di erent fra tions need to
be drawn. Indeed, all this is determined by TEX, using a ni e blend of s ien e and art.
How to layout mathemati al formulae, is the rst problem we will see in this hapter.
This will turn out to be a rather interesting appli ation of stru tural re ursion. We will
then go on to another important, but more lassi al appli ation: using trees to maintain an
ordered set in memory.

22.1 Layout of mathemati al formulae


Our goal in some sense, is to write a program that does what TEX does. That, of ourse,
is extremely ambitious! We will instead onsider a very tiny version of the formula layout
problem. Spe i ally, we will only onsider formulae in whi h only the 2 arithmeti operators
+ and / are used. Our program must take any su h formula, written in a language like
the TEX language, and produ e a layout for it. This layout must then be shown on our
graphi s anvas. As you will dis over in the Exer ises, on e you master sum and division,
implementing other operators and more omplex operations su h as summations using the
P
symbol is not mu h more diÆ ult. Of ourse, all this will still be far from what TEX
a omplishes. 1

22.1.1 Input format


The rst question, of ourse, is how should we spe ify the formula to the program. One
possibility is to just use the TEX language, sin e that is well known. However that seems too
elaborate, after all we only have 2 operators. Another possibility is toa spe ify the formula in
the style used in C++ to spe ify mathemati al formulae, e.g. to get b we will supply a/b as
TEX is a omplete do ument pro essor. Furthermore, even for the purpose of laying out mathemati al
1
formulae, it is very sophisti ated. For example, it adjusts sizes of the text, whi h our program will not.
Abhiram Ranade, 2013. Do not distribute 366
input, and so on. This will work, but turns out it will make it slightly harder to write our
program, as you will see later. So to keep matters simple, we use a slight variation on the
C++ style.
We will require that the formula be spe i ed in the style used in C++, with the operands
to the + operator as well as the / operator pla ed in parentheses.
So as a simple example, whereas in C++ you ould write a/b, to spe ify this to our
program you would have to write (a/b), be ause the rule says that the operands to every
operator must be inside parentheses. Figure 22.1 gives some more examples. As you an
see, the input required by our program is more verbose as ompared to what is required
to spe ify the formula in C++. In the exer ises we will explore the issues in allowing less
verbose input.
We should note an interesting feature of our input format. You will note that any formula
written in the style des ribed above will have one of the following forms:
x : where x is a primitive formula, i.e. an identi er or a number.
(f+g) : where f and g are themselves formulae. For example, in ((((x+1)/(x+3))+(x/5))+6)
we have f = (((x+1)/(x+3))+(x/5)) and g = 6
(f/g) : where f and g are themselves formulae. For example, in (a/(b+ )) we have f = a
and g = (b+ ).
In other words, formulae are built up either using primitive formulae (\base ase") or other
formulae. Hen e a formula is said to have a re ursive stru ture. The re ursive stru ture will
be very useful.
22.1.2 Layout \by hand"
Before jumping into a dis ussion of how to do a layout on a omputer, it is worth onsidering
how we would do a layout using paper and pen il. A tually, this time we will also use s issors
and glue!
Before reading further, you are invited to think about how you will do a layout. After
all, you have been writing out formulae sin e high s hool! You will perhaps nd the problem
to be slightly tri ky.
It is onvenient to onsider the problem in a re ursive manner. First the base ase.
Suppose the formula you wish to layout is a primitive formula. In this ase, the requirement
is simple: you print out the number or the identi er wherever it is to be printed out.
Next onsider non-primitive formulae, i.e. f=g or f + g, where we have omitted the
parentheses for brevity. For this we will assume that we are given re tangular pie es of
paper with the layouts of f; g respe tively. The re tangles are bounding boxes for the layouts,
i.e. they are the smallest re tangles having horizontal and verti al sides that ontain the
layouts. Our goal is to sti k these on a larger pie e of paper, with a horizontal bar or +
drawn suitably to produ e the layout of f=g or f + g as desired. How did we get the layouts
of f; g in the rst pla e? As you may guess, the answer is: re ursion!
First onsider how we might produ e the layout for f=g. Clearly, the formula f must be
at the top, below whi h there must be a horizontal bar denoting the division, below whi h
there must be the formula g. The length of the bar must equal the maximum of the widths
Abhiram Ranade, 2013. Do not distribute 367
of the formulae f; g. Further, f; g must be entered with respe t to the horizontal bar. Here
is an example.
a
2
1+b
a
We have shown the bounding boxes for f; g as well as f=g. The gap between the bounding
boxes has been put in for readability; if you are utting paper, there will be no gap.
Next onsider f + g. In this ase f must appear to the left, then the symbol + must
appear, and g must appear to the right. However, how do we align f; g with the + symbol?
This will depend upon what is inside the formulae, as the following example will illustrate.

a+ 12
a
+b
Here we have shown the layout of f + g where f = a and g = a b . As you an see, how the
2
1+

+ symbol aligns with f; g depends upon what is in f; g. Both f; g appear to have a ertain
operator level whi h must align with the horizontal bar of the intervening +. For f , whi h
is a primitive formula, the operator level seems to be just the level of its enter, whi h as
you see is aligned with the horizontal bar of the +. However, for g whi h is itself a ratio of
2 and a + b , the operator level seems to be the horizontal bar between the numerator 2 and
1

the denominator a + b.
1

So if we wish to layout f + g we will need to know the operator levels of f; g. In the


dis ussion above we have seen how to determine the operator level a formula whi h is either
primitive, or whi h is a ratio. We will now dis uss how to nd the operator level of a sum.
To understand this, onsider the following example.

+a + 2
d 1+b
a
In this, f is itself a sum of d and a. As you will see the sum inside f must align with the
sum outside. Thus the operator level of f is the level of the + inside it. In other words, the
operator level of a sum v + w is the level of the + between the summands v; w.
Using what we have stated above, you should indeed be able to layout any formula using
paper, pen il, s issors and glue. You are requested to think this over arefully, a tually trying
out some examples if ne essary. This kind of introspe tion over what you might onsider
\obvious" and \routine" is ru ial for developing algorithms.
Next we turn to developing the program. Our goal will be to produ e a layout identi al
to the one as would be produ ed by the pro edure we des ribed above.
Abhiram Ranade, 2013. Do not distribute 368
+

/
+
/

+ + 6
+ /
a

b c x 1 x 3 x 5

(a)
(b)

Figure 22.2: (a) Tree for b a (b) Tree for xx + x + 6


+
+1
+3 5

22.1.3 Representing mathemati al formulae


The re ursive stru ture of a mathemati al formula is useful in representing a formula on
a omputer. The stru ture will be omes more obvious if we rst draw the formula as a
rooted tree, sort of like the exe ution tree of Figure 10.5. Figure 22.2 shows two formulae
drawn as rooted trees. Leaf nodes, i.e. nodes that have no hildren orrespond to primitive
formulae. Internal nodes (i.e. nodes that are not leaves) are asso iated with an operator.
A subtree, i.e. any node and all the nodes below it, represents a subformula used to build
up the original formula. For example, in Figure 22.2(a), the subtree in luding and beneath
the node labelled + orresponds to the subformula b + . Similarly, in Figure 22.2(b), xthe
node labelled / on the left side and the nodes below it orrespond to the subformula x , +1

whereas the xnode labelled / on the right and the nodes below it together orrespond to the
+3

subformula .
Figure 22.2, suggests that to represent a formula, we should rst represent the nodes of
6

the tree, and then represent the onne tions between the nodes, and then we should be done!
It seems natural to use a stru ture to represent tree nodes. The stru ture should ontain
the information asso iated with a node, e.g. whether the node is asso iated with an operator,
and if so whi h one, or if the node is asso iated with a primitive formula, and if so whi h
one. The natural way to represent onne tions between the nodes is to use pointers. So we
de ne a stru ture Node as follows.
stru t Node{ // we give member fun tions later
string value;
har op;
Node* lhs;
Node* rhs;
};

This stru ture an be used to express primitive as well as non primitive formulae. If a
formula is primitive, i.e. onsists of an identi er or a number, we will store that symbol or
number in the member value as a hara ter string. Otherwise, the formula must be a binary
Abhiram Ranade, 2013. Do not distribute 369
omposition of two smaller formulae. In this ase, we store the operator in the op member,
and we store pointers to the roots of the subformulae in the members lhs,rhs.
It is useful to have onstru tors for both ways of onstru ting formulae.
Node::Node(string v){ // primitive onstru tor
value = v;
op = 'P'; // onvention: 'P' in op denotes primitive formula.
lhs = NULL;
rhs = NULL;
}

Node::Node( har op1, Node* lhs1, Node* rhs1){ // re ursive onstru tor
value = "";
op = op1;
lhs = lhs1;
rhs = rhs1;
}
Here is the rst way we an onstru t the representation for the formula b a in our program.
+

Node aexp("a");
Node bexp("b");
Node exp(" ");
Node bplus ('+', &aexp, &bexp);
Node f1('/', &aexp, &bplus );
Thus f1 will be the root of the tree for the formula b a . Thus we an say that f1 represents
the formula. Or alternatively we an also onstru t a representation more dire tly:
+

Node f2('/', new Node("a"),


new Node('+', new Node("b"), new Node(" "))
);
An important point to note here is that the operator new when used on a onstru tor all
returns a pointer to the onstru ted obje t, whi h is exa tly what we want as an argument
to our re ursive onstru tor. Thus f2 will also be a root of the tree for the formula b a , and
an thus be said to represent the formula.
+

There is a di eren e between the two onstru tions, however. In the rst onstru tion, all
memory for the formula omes from the urrent a tivation frame. In the se ond onstru tion,
all memory ex ept for the node f2 omes from the heap, the memory for f2 omes from the
urrent a tivation frame.
On e we have a representation for formulae, our task splits into two parts:
1. Read the formula from the input in the format spe i ed in Se tion 22.1 and build a
representation for it using the Node lass.
2. Generate the layout for the onstru ted representation. It is natural to de ne member
fun tions on Node whi h will generate the layout.
We onsider these steps in turn.
Abhiram Ranade, 2013. Do not distribute 370
22.1.4 Reading in a formula
We now show how to read in the formula and build a representation. It is easiest to write
our ode as a onstru tor.
For simpli ity, we will make two assumptions: (a) Ea h number or identi er is exa tly
one hara ter long, (b) there are no spa es inside the formula. In the exer ises you are asked
to write ode whi h allows longer primitive formulae and also spa es.
We read the formula hara ter by hara ter and build a representation as we go along.
To read a hara ter from a stream infile, we an use the operation infile.get() whi h
returns the next hara ter as an integer value.
If the very rst hara ter read is a number or a letter, then we have indeed read a
primitive formula and we an stop.
If what is read is the hara ter '(', then we know that the user is supplying us a non-
primitive formula. In that ase we know that we must next see in su ession (a) the left
hand side formula, (b) an operator, and ( ) the right hand side formula. To read in the left
hand side formula as per (a), we merely re urse! After the formula has been read in step
(b), we read a single hara ter, and it had better be an operator, as per (b). After that we
re urse again, in order to get the right hand side formula, as per ( )! And after that we
must see a ')' to mat h the initial open parenthesis. So our ode to read in a formulae is
extremely simple, even though the formulae themeselves an be very ompli ated.
Node::Node(istream &infile){
har =infile.get();
if(( >= '0' && <= '9') || // is it a primitive formula?
( >= 'a' && <= 'z') ||
( >= 'A' && <= 'Z')){
lhs=rhs=NULL; op='P'; value = ;
}
else if( == '('){ // does it start a non-primitive formula?
lhs = new Node(infile); // re ursively get the lhs formula
op = infile.get(); // get the operator
rhs = new Node(infile); // re ursively get the rhs formula
if(infile.get() != ')')
out << "No mat hing parenthesis.\n";
}
else out << "Error in input.\n";
}
Now we an write a part of the main program.
int main(){
Node f( in);
}
This will all our latest onstru tor with the parameter infile being in, i.e. the formula
will be read from the keyboard. You may type in something like
(a/(b+ ))
and it will reate f, just as we reated f2 earlier.
Abhiram Ranade, 2013. Do not distribute 371
22.1.5 Drawing the formula: overview
The input to the drawing step is a formula, and an indi ation of where it is to be drawn on
the anvas. It is natural that the formula is presented to us as a node f, whi h is the root of
the tree representing the formula that is to be drawn. We will abuse terms and let f denote
the formula as well. As to where to draw it, presumably the user will tell us something like
\Draw the formula below and to the right of some point (x; y)". The values x; y will be given
by the user. Then our goal is to draw the given formula f su h that the top left orner of
its bounding box is at the point (x; y) on the anvas.
How do we perform our task? It would seem natural to onsider re ursion. Presumably
primitive formulae are the base ase, and learly we an write out the required text wherever
required. So let us onsider a non primitive formula f=g. Perhaps we should re ursively
draw f then draw the horizontal bar denoting the division, and then re ursively draw g.
However, in order to draw f we need to know the width of g, so that we an enter them
with respe t to the horizontal bar (Se tion 22.1.2). To draw g we need to know the width
of f , and also the height of f .
So it is natural to have a al ulation phase before we draw anything. In this phase we
al ulate the width and height of the layouts of the di erent subformulae in our formula.
We also determine the operator level. More spe i ally we determine for ea h subformula
a parameter alled des ent, whi h is the distan e of the operator level from the bottom of
the formula. Likewise we de ne the as ent to be the distan e of the operator level from the
top of the formula. On e we know the width, height, as ent and des ent, we start the a tual
drawing. Note that the height is just the sum of the as ent and the des ent, so we ignore the
height in what follows. If f is a formula, we will use wf ; af ; df to denote the width, as ent
and the des ent of the layout of f .
Our algorithm to determine these parameters will be re ursive. Suppose f is some iden-
ti er x. Then the width of x an be determined using the all textWidth(x). The height of
x does not depend upon x, and an be determined by alling textHeight(). We will assume
that the + symbol must align with the enter of x. Thus we will have as ent and des ent to
be both textWidth(x)/2.
So next onsider formulae of the form (f+g). This is shown in Figure 22.3(a). The
dashed line is the operator level, for f; g and also f + g. From the pi ture we have:
af g = max(af ; ag )
+ (22.1)
df g = max(df ; dg )
+ (22.2)
wf g = wf + wo + wg
+ (22.3)
where wo is the width of the + symbol. In the gure we have also marked the top left orners
of the layouts f; g; f + g. This will be used in Se tion ??.
In Figure 22.3(b) we onsider formulae of the form f=g. We rst note that
wf =g = max(wf ; wg ) (22.4)
We remarked earlier that the operator level of f=g is at the position of the horizontal bar.
Above the bar we have the entire formula f and half the height needed to a ommodate the
horizontal bar. Similarly below we have the formula g and half the height required for the
Abhiram Ranade, 2013. Do not distribute 372
horizontal bar. Thus we get
df =g = dg + ag + ho=2 (22.5)
af =g = df + af + ho =2 (22.6)
Here ho denotes the height needed to a ommodate the horizontal bar.
As you an see, knowing the width, as ent, des ent of f; g we an al ulate the width,
as ent, des ent of f + g and also f=g. We will write this al ulation as a re ursive fun tion
setSizes. We will have members width, as ent, des ent in ea h Node in whi h setSizes
will store the values. So our stru ture be omes:
stru t Node{
Node *lhs, *rhs;
har op;
string value;
double width, height, des ent;
Node(string v);
Node( har op1, Node* lhs1, Node* rhs1);
Node(istream& infile);
void setSizes();
void draw(float lx, float y); // to a tually draw
}

We have already given the implementations for the onstru tors. The implementation for
setSizes follows the ideas des ribed above. Note that f orresponds to lhs and g to rhs.

onst double h_o = 20; // spa e for horizontal bar

void Node::setSizes(){
swit h (op){
ase 'P': // Primitive formula
width = textWidth(value);
as ent = textHeight()/2; des ent = textHeight()/2;
break;
ase '+': // ase f+g
lhs->setSizes();
rhs->setSizes();
des ent = max(lhs->des ent, rhs->des ent);
width = lhs->width + textWidth(op) + rhs->width;
as ent = max(lhs->as ent, rhs->as ent);
break;
ase '/': // ase f/g
lhs->setSizes();
rhs->setSizes();
width = max(lhs->width, rhs->width);
as ent = h_o/2 + lhs->as ent + lhs->des ent;
Abhiram Ranade, 2013. Do not distribute 373
(xf +g ; yf +g )
(xg ; yg )
(xf ; yf ) ag af +g
af
hf +g

dg
df df +g

wf wo wg

wf +g
(a) Layout of f + g
(xf =g ; yf =g ) (xf ; yf )

hg

wf

hf =g
Operator level ho
of f=g (xg ; yg )

hg
wg

wf =g
(b) Layout of f=g
Figure 22.3: Composing layouts
Abhiram Ranade, 2013. Do not distribute 374
des ent = h_o/2 + rhs->as ent + rhs->des ent;
break;
default: out << "Invalid input.\n";
}
}
Next we onsider how to a tually draw the layout. We will de ne a draw member fun tion
taking as arguments the desired oordinates x,y of the top left orner of the bounding box.
The implementation will of ourse be re ursive.
If the formula being drawn is primitive, then we simply write the orresponding text.
For this we reate a text obje t and imprint it. In reating text we must spe ify the enter;
thus if we want the top left orner to be (x,y) the text must be entered at (x+width/2,
y + as ent).
If the formula beind drawn is of the form f + g, then we an see where to draw it by
onsulting Figure 22.3(a). As an be seen, the x oordinate of the top left orner of f is the
same as that of f + g, i.e.
xf = xf g
+ (22.7)
The box of g is o set to the right by the amount wf + wo. So we have
xg = x f g + w f + w o
+ (22.8)
As to the y oordinates, note that the top left orners of f + g; f; g are above the operator
level by af g ; af ; ag . Thus it follows that
+

yf = y f g + a f g a f
+ + (22.9)
yg = y f g + a f g a g
+ + (22.10)
Finally, the + symbol must be drawn at the operator level whi h is wf + wo=2 to the left
and af g below the top left orner of f + g. This is used in the ode below. Note that f
+
orresponds to the member lhs, and g to the member rhs.
void Node::draw(double x, double y){
swit h(op){
ase 'P':
Text(x + width/2, y + as ent, value).imprint();
break;
ase '+':
lhs->draw(x, y + as ent - lhs->as ent);
rhs->draw(x + lhs->width + textWidth(op), y + as ent - rhs->as ent);
Text(x + lhs->width + textWidth(op)/2, y + as ent,
string(1,op)).imprint(); // draw the '+' symbol
break;
ase '/':
Line(x, y + as ent, x + width, y + as ent).imprint(); // horizontal bar
lhs->draw(x + width/2 - lhs->width/2, y);
Abhiram Ranade, 2013. Do not distribute 375
rhs->draw(x + width/2 - rhs->width/2, y + h_o/2 + as ent);
break;
default: out << "Invalid input.\n";
}
}
The last ase is of drawing an expression of the form f=g. How to position f; g and how to
draw the horizontal bar an be worked out from Figure 22.3(b). We omit the details.
22.1.6 The omplete main program
Here is the main program.
int main(){
initCanvas("Formula drawing");
Node f( in);
f.setSizes();
f.draw(0,0); // top left of formula must align with top left of anvas.

wait(5);

22.1.7 Remarks
Re ursive stru tures appear in many real life situations. For example, the administrative
heirar hy of an organization is re ursive, e.g. there is a dire tor/president/prime ministers,
to whom report deputies, to whom report further deputies.
It is natural to asso iate a tree with a re ursive stru ture. The substru tures are denoted
as subtrees, and the element joining the subtrees, e.g. the dire tor will orrespond to the
root. In the ase of mathemati al expressions, the operator orresponds to the root, and the
sub expressions orrespond to the subtrees.
You may be wondering why we require that the formulae to be layed out be spe i ed in
our verbose format; why not just spe ify them as they might be in C++? It turns out that
getting a program to read formulae in C++ like languages is a lassi al omputer s ien e
problem, in its most general setting. If you pursue further edu ation in Computer S ien e,
you will perhaps study it in a ourse on ompiler onstru tion, or automata theory. For now
suÆ e it to say that reading C++ style expressions is a diÆ ult problem. However, in the
exer ises you are en ouraged to think about it.

22.2 Maintaining an ordered set


We onsider the following abstra t problem: how to maintain a set whose elements an be
integers. As the program exe utes, integers an get added into the set. In addition, the
program must respond to membership queries, i.e. given some integer x, the program must
determine if x is present in the set. For simpli ity, we only onsider these two operations,
Abhiram Ranade, 2013. Do not distribute 376
insertion, and membership. But you an see that other operations might also be useful, e.g.
removing an element from a set, or nding the number of elements smaller than a given
number z. Even more generally, you ould let the elements of the set be omplex obje ts,
e.g. a stru ture ontaining the roll number and marks of a student. Then you might merely
want to know if a student belongs to a lass (membership), or you might want to know the
number of students who got fewer marks than some number z. The ideas we dis uss for
our simple problem will be of use in these more ompli ated situations as well, as you will
dis over in the exer ises.
The simplest way to store a set is to use an array, or a ve tor (Chapter 20). To add an
element, we simply use the push ba k fun tion. To determine if an element is present, we
an s an through the ve tor. The s anning operation, however, is rather time onsuming:
we need to examine every element stored in the ve tor. A slight improvement is to keep the
elements sorted in the ve tor. Then we will be able to perform membership queries using
binary sear h, whi h would go very fast. However, when a new element is to be inserted, we
will need to nd its position, and shift down the elements larger than it. This operation will
on the average require us to shift half the elements, and thus is quite time onsuming. So
again this is unsatisfa tory.
22.2.1 A sear h tree
There is a way to organize the elements of the set so that insertions as well as membership
queries an be done very fast: we store them in a so alled sear h tree. First we dis uss
the orresponden e between a set and a sear h tree onsidered abstra tly. Then we dis uss
how the tree an be represented on a omputer.
A sear h tree is a rooted tree in whi h elements of the set are asso iated with ea h tree
node. Ea h node has upto two outgoing bran hes, denoted left, and right. The left bran h (if
any) onne ts the root to the left subtree, and the right bran h (if any) to the right subtree.
A subtree is likewise a root with upto two bran hes. A subtree with no bran hes is alled a
leaf. Here is the key property that we require for a tree storing elements to be a sear h tree:

Values of elements in the  Value of element  Values of elements in the


left subtree of node v at node v right subtree of node v
Figure 22.4 shows example of a sear h tree (part (a),(b)) and a non-sear h tree (part
( )). In ea h ase, we have shown the value of the element stored at ea h node. Thus the
tree in (a) would represent the set f18; 34; 40; 56; 70g, while the one in (b) would represent
f10; 12; 18; 30; 30; 35; 36; 50; 51; 60; 65; 77; 78; 86; 93g. In ( ), the subtrees beneath the node
with element 34 do not satisfy the sear h tree property: the right subtree is required to
ontain elements larger than 34 but it a tually ontains the element 30. So the tree in ( )
will not represent any set, as per our s heme.
It should be lear how to represent sear h trees. The stru ture needed is almost the same
as what we had for storing mathemati al expressions.
stru t Node{
Node *lhs, *rhs;
Abhiram Ranade, 2013. Do not distribute 377
34

56
50
18

77
30
40 70

(a) 35
12 60 86

34

10 18 30 36 51 65 78 93

56
(b)
18

30 70

(c)

Figure 22.4: Examples (a),(b) and non-example ( ) of sear h trees


int value;
}
This is identi al to what we had in Se tion 22.1.3, ex ept that we do not have the member
op, whi h is not needed here. We do have a member value whi h will hold the set element
stored at the node. As before the members lhs and rhs will pointers to the root nodes of
the left and right subtrees.
22.2.2 The general idea
We explain with an example why sear h trees are useful for storing sets. Suppose we have
somehow onstru ted the sear h tree in memory. Suppose now the user presents us a mem-
bership query, say determine whether some number x is present in the tree. How do we
do this? Remember that when we build the tree, we will only be able to refer to the root
dire tly. To get to the other nodes, we need to follow the left or right pointers. So our
problem is: we know the root of the tree that ontains the elements, and we are given x,
and we wish to determine if x is present at any node of the tree.
Sin e we only know the root of the tree, we an only ompare x with the number stored
at the root. If the number happens to be x, then we an immediately respond with a true
response. If the number at the root is not x, then we need to do more work. So we ask
whether x is smaller or larger than the number at the root. If x is smaller, then we know
that it an only be in the left subtree. This is be ause of the sear h tree property: the
numbers in the right subtree an only be larger than the number at the root, so there is no
Abhiram Ranade, 2013. Do not distribute 378
need for us to ompare x to them. Thus now we an re urse on the left subtree! Similarly,
if x is larger than the number at the root, then we re urse on the right subtree, i.e. try to
determine if x is present in the right subtree. The re ursion stops if we are for ed to sear h
an empty subtree { if that happens we know that the number is not present and we return
false.
As an example, suppose we have in memory the tree in Figure 22.4(b). Suppose we want
to know if x = 63 is in the tree. Then we would ompare x to the number at the root, 50.
Finding that x is bigger, we would de ide that we only need to sear h the right subtree. The
root node ontains a pointer to the root of the right subtree, so we use that to get to root
of the right subtree. So next we ompare x with the number stored there, whi h is 77. This
time we realize that x whi h we are looking for is smaller. So we know we must sear h the
left subtree beneath 77. So we follow the left pointer this time and get to the node ontaining
the key 60. This time we he k and realize that x is in fa t larger. So we follow the right
bran h out of the node ontaining number 60. So we get to the node ontaining the number
65. Sin e x is smaller than 65, we know we must go to the left subtree. But there is no left
subtree for the node ontaining 65! So in this ase we have determined that our number x
is not present in the set. So we return false as the answer.
Noti e that we have been able to get to an answer by examining a very few nodes: those
nodes ontaining 50, 77, 60, and 65. We did not examine the other nodes, yet we dedu ed
that the number x = 63 ould not have been present in the other nodes: be ause we know
that the tree obeys the sear h tree property. So this is how we an give a fast response.
If at this point you feel that our argument is too sli k, you would be right. The argument
given above depends very mu h upon the shape of the tree in whi h the set was stored. The
tree of Figure 22.4(b) was balan ed, i.e. both subtrees under ea h node had exa tly the same
number of nodes. If the tree is unbalan ed, then the eÆ ien y an be ome mu h worse. We
take up this aspe t in Se tion 22.2.5. For now, we will assume that somehow the trees that
we en ounter will be balan ed, or nearly balan ed. This assumption an be justi ed, as you
will see in Se tion 22.2.5.
Next we onsider the operation of inserting elements into the set. For this, we do some-
thing similar to he king if a number is present. Suppose we wish to insert the number x.
Then we rst he k the number at the root. If x is smaller, then we know that it must be
inserted in the left subtree, or else the sear h tree property will be violated. So we re ur-
sively try to insert in the left subtree. Similarly if x is larger than the number at the root,
we re ursively try to insert in the right subtree. The pre ise details will be ome lear when
we give the ode.
22.2.3 The implementation
We will indeed represent a set as a tree. In the last se tion, we used the root node of the
tree as the representative of the tree, i.e. the point from whi h we an get a ess to the rest
of the tree. This does not quite work in the present ase.
There is a slight te hni ality that we need to onsider. How do we represent an empty
set? If the representation ontains any Node obje t whatsoever, then that obje t will store
a value, and hen e will not represent an empty set. So learly we annot represent a set by
the node denoting the root of the tree. Instead, we represent a set by a pointer to the node
Abhiram Ranade, 2013. Do not distribute 379
denoting the root. Now if we want to represent the empty set, we merely set this pointer to
NULL.
For onvenien e, we will put the pointer to the root inside a lass Set, whi h will ontain
a data member we will all root, whi h will point to the root node of the tree.
stru t Set{
Node* proot; // pointer to tree root.
Set(){proot = NULL;}
// more to ome.
}
The lass will have more member fun tions, but we have put in a onstru tor whi h sets the
member proot to NULL, indi ating that the set is empty. Given this de nition, we may write
Set mySet; // automati ally initialized to NULL, by the onstru tor.
and we will have de lared a set in our program. This is ni er than saying Node* mySet;.
We will also hange the Node stru t slightly. Instead of using it as given earlier, we will
de ne it as follows.
stru t Node{
Set lhs, rhs;
int value;
};
Noti e that this de nition is really the same as the old, after all Set ontains no other data
members ex ept proot of type Node*. But making the members lhs, rhs of type Set will
make the ode easier to read. Many programmers might sti k with the old de nition, so the
Exer ises ask you to do that also.
We will implement the membership query as a bool fun tion find taking as argument
the element to look for. The ode for the fun tion follows dire tly from what we dis ussed
earlier.
bool Set::find(int elt){
if(proot == NULL) return false;
else{
if(elt == proot->value) return true;
else if(elt < proot->value) return proot->left.find(elt);
else return proot->right.find(elt);
}
}
As we said, if we rea h an empty tree, the element is not present, hen e the rst statement
returns false. Else we ompare the element being sear hed, elt, with the value at the root of
the set. Note however that Set merely ontains a pointer proot to the root, hen e the value
stored at the root is proot->value. If elt is equal to proot->value, we have dis overed that
elt is indeed in the set, and so we return true. Else if elt is smaller than proot->value,
we must sear h the left subtree, proot->left. Similarly the right.
Before we dis uss insertion, it is useful to see a onstru tor for Node.
Abhiram Ranade, 2013. Do not distribute 380
Node::Node(int v){
value = v;
}
This sets the value member to the given value, but does nothing to the other members
lhs, rhs. Is this OK? If nothing is spe i ed, then these members will be initialized by their
default onstru tors. But the default onstru tor for Set auses the member proot to be
set to NULL. So the members lhs, rhs would indeed get initialized orre tly.
Now we ome to insertion. We will implement insertion by a fun tion insert taking the
element to be inserted as the argument. The ode is re ursive and follows our dis ussion.
void Set::insert(int elt){
if(proot == NULL){proot = new node(elt);}
else{
if(elt == proot->value) return; // no need to insert again.
if(elt < proot->value) proot->left.insert(elt);
else proot->right.insert(elt);
}
}
If our set is empty, then proot will be NULL. So in this ase, we will insert a node ontaining
the new element. This is what the rst statement does. If the set is not empty, then proot
must be non NULL, and in this ase we will ome to the se ond line of the fun tion. We will
he k if the value at the root is equal to the element being inserted, if so, we do nothing,
there is no need to insert the same element again. But if the value being inserted is smaller,
then we will insert into the left subtree. Similarly for the right.
The exer ises ask you to de ne other operations, e.g. printing the set. As you might
guess, most operations on trees an be naturally ta kled using re ursion.
22.2.4 A note about organizing the program
Note that our de nition of Node refers to the de nition of Set, and vi e versa. Whi h one
must pre ed the other? The de nition of Set only refers to a pointer to Node. Hen e we
an de ne that after putting a forward referen e to Node. The de nition of Node however
mentions a member of type Set. Hen e it must ome after the de nition of Set. The
implementation of the member fun tions in Set an ome any pla e following the de nition
of Set.
22.2.5 On the eÆ ien y of sear h trees
We rst observe that there an be many binary sear h trees that ontain a given set of
numbers. Figure 22.5 give two additional trees whi h ontain the same numbers as Fig-
ure 22.4(a).
There an be other trees also, in fa t you should be able to prove that a set with 5
elements an be represented by 42 trees. Clearly, the time required to answer membership
queries will depend upon whi h of these 42 trees has arisen during the exe ution.
Abhiram Ranade, 2013. Do not distribute 381
56 18
34

40
34 70
56

70
18 40

(a) (b)

Figure 22.5: Other trees representing the same set as Figure 22.4(a)
Of these trees, the worst is the one in Figure 22.5(b). In this, the smallest value is at
the root. The se ond smallest is at the right hild of the root. The third smallest is at its
right hild, and so on. Our program will build this \tree" if the numbers were inserted in
as ending order. Suppose the user asked to sear h for 100. Then the sear h would start at
the root, and go rightward, examining every node in the tree. In omparison, if the set had
been stored as Figure 22.5(a), then the we would rst ompare 100 to the value 56, and then
to the value 70, and on lude that 100 is not in the set. So learly the tree of Figure 22.5(b)
is bad for the purpose of he king if 100 is in the set. Indeed, you will observe that sear hing
in the tree of Figure 22.5(b) is essentially like sear hing in a sorted ve tor.
So perhaps we ould make a general observation: our find fun tion will examine the
values stored in some path starting at the root and ending at the leaf. So if we want the
program to run fast, then we would like all su h paths to be short. It is ustomary to de ne
the height of a tree as the length of the longest root leaf path in a tree. Thus our hope is
that as the program exe utes, the tree we get has small height.
Theorem 3 Suppose numbers from a ertain set jS j are inserted into a sear h tree using
our insert fun tion. Then if the order to insert is hosen at random, then the expe ted
height of the tree smaller than 2 ln jS j, i.e. twi e the natural log of the number of elements
in the set.
The proof of the theorem is outside the s ope of this book, but the exer ise asks you to
validate it experimentally.
Let us try to understand what the theorem says using an example. Suppose we have
a set with size 1000, whose elements are inserted in random order into our tree. Then on
the average we expe t to see that the height will be at most 2 ln1000  14. Thus when we
perform membership queries (or further insertions) we expe t to ompare the given number
with the numbers in at most 15 nodes in the tree.
You ould also ask what are the worst and best heights possible for 1000 nodes. Clearly, if
the numbers ame in in reasing order, then we would get just one path of length 1000 { that
would be the height. The other extreme is a tree in whi h we keep on inserting nodes as lose
to the root as possible. So we would start by inserting two nodes dire tly onne ted to the
root, then two nodes onne ted to ea h of these, and so on, till be inserted 1000 nodes. So we
would have 1 node (the root itself) at distan e 0, 2 nodes at distan e 1, 4 nodes at distan e
Abhiram Ranade, 2013. Do not distribute 382
2 and so on till 256 nodes at distan e 8, and the remaining 1000 256 128    1 = 489
nodes at level 9. So the height of this tree would be 9.
So it is ni e to know that on the average we are likely to be mu h loser to the best height
rather than the worst. Or alternatively, on the average our find and insert fun tions will
run fast.
22.2.6 Balan ing the sear h tree
You might be bothered that the above program will work fast \on the average", but might
take very long if you are unlu ky. What if the numbers in the set got inserted in as ending
order, or some su h bad order?
In that ase there are advan ed algorithms that try to balan e the tree as it gets built.
This is done by modifying an already built tree, and say hanging the root. With su h
rebalan ing, it is indeed possible to ensure that the height of the tree remains small. Further,
rebalan ing algorithms have been developed that also run very fast. But this is outside the
s ope of this book.
22.2.7 Sear h trees and maps
The (index,value) pairs onstituting a map from the C++ Standard Library are stored
using binary sear h trees. The ordering rule is that all pairs in the left subtree must have
index smaller than that at the root, whi h in turn must be smaller than the indi es of the
elements in the right subtree. Further, the tree is kept balan ed as dis ussed above. Thus
making an a ess su h as value[index℄ happens fairly fast, i.e. in time proportional to
log n, where n is the number of pairs stored in the map.
2

22.3 Exer ises


1. Extend the formula drawing program so that it allows the operators '*', '+' and
'-'. This is not entirely trivial: make sure your program works orre tly for input
((x+3)*(x-2)). You will see that you may need to add parenthesization to the output.
For simpli ity, you ould parenthesize every expression when in doubt.
2. Add an operator '^' to denote exponentiation in the formula drawing program. In
other words, Node('^',Node("x"), Node("y")) whi h will print as xy .
3. Allow the impli it multipli ation operator, i.e. it should be possible to draw x uv .
4. Suppose the user gives the position of the top left orner of the bounding box of the
formula. Show how you ould do this. Also if the user asks that the formula be entered
at some given point.
5. Write a onstru tor fun tion whi h takes as input a single referen e argument, infile&
whi h is a referen e to an istream, and onstru ts an expression based on what it
reads there. The asso iated le should ontain valid expressions but written in a pre x
form. Note that in the pre x form, the operator omes rst, and every operator is
Abhiram Ranade, 2013. Do not distribute 383
parenthesized. Thus b a will be written as (/ a (+ b ). Observe that this way of
writing expressions also has a re ursive stru ture. Thus your onstru tor will also be
+

re ursive. For simpli ity assume that ea h primitive expression is a single hara ter.
Further assume for simpli ity that there are no spa es in the input. Thus the above
expression would appear in the le as (/a(+b )). Note that get is a member fun tion
on istreams that an be used to read single hara ters. Thus infile.get() reads the
next hara ter from infile and returns its value.
6. Modify the ode above so that it is allowed to ontain spa es.
7. The expression infile.peek(); returns the next hara ter in the le without a tually
reading it. Use this to modify the ode above so as to allow primitive expressions to
be longer than a single hara ter. Assume that onse utive primitive expressions will
be separated by a spa e.
8. How will you represent integration with lower and upper limits, and the integrand? In
other words, you should be able to draw formulae su h as
Z 1
x2 dx
0 x2 + 1
Hint: The best way to do this is to use a ternary operator, say denoted by the letter
I, whi h takes as arguments 3 formulae: the lower limit L , the upper limit U, and the
expression E to be integrated. You ould require this to be spe i ed as (L I U E).
9. As we have de ned, our formulae annot in lude bra kets. Extend our program to
allow this. You ould think of bra kets being a unary operator, say B. Sin e it is
our onvention to put the operator se ond, you ould ask that if a formula F is to be
bra keted, it be written as (F B). Make sure that you draw the bra kets of the right
size.
10. You may want to think about how the program might hange if the formula to be
layed out is spe i ed in the standard C++ style, i.e to draw a + b the input is given
as a+b/ rather than (a+(b/ )) as we have been requiring. The key problem as you
might realize, is that after reading the initial part a+b of the input, you are not sure
whether the operator + operates on a,b. This is the ase if the subsequent operator,
if any, has the same pre eden e as +. However, if the subsequent operator has higher
pre eden e, as in the present ase, then the result of the division must be added to a.
So you need to look ahead a bit to de ide stru ture to onstru t. This is a somewhat
hard problem, but you are en ouraged to think about it. Note that your job is not only
to write the program, but also argue that it will orre tly deal with all valid expressions
that might be given to it.
11. Add a deriv member fun tion, whi h should return the derivative of a formula with
respe t to the variable x. Use the standard rules of di erentiation for this, i.e.
d(uv )
dx
= v du + u dvdx dx
Abhiram Ranade, 2013. Do not distribute 384
This will of ourse be re ursive. You should be able to draw the derivatives on the
anvas, of ourse.
12. You will noti e that the result returned by deriv often has sub-expressions that are
produ ts in whi h one operand is 1 and sums in whi h one operand is 0. Su h expres-
sions an be simpli ed. Add a simplify member fun tion whi h does this. This will
also be re ursive.
13. Suppose you want to represent sets using just the Node de nition from Se tion22.2.1.
Then to reate a set mySet whi h is initially empty, I would write:
Node* mySet = NULL;

To implement membership and insertion queries, we ould merely adapt the fun tions
insert and find of Se tion 22.2.3. Note however, that those were member fun tions
for Set, whis is really of type Node*, so they annot be ome member fun tions for
Node. Thus they must be ome ordinary fun tions. Here is a suggested adaptation of
insert:

void insert(node* set, int elt){


if(set == NULL){set = new node(elt,NULL,NULL);}
else{
if(elt < set->value) insert(set->left, elt);
else insert(set->right, elt);
}
}

Do you think it is a faithful adaptation? Does it work? Hint: Be areful about whether
you should use all by referen e or by value.
Here is an adaptation of the nd method.
bool find(node* set, int elt){
if(set == NULL) return false;
else{
if(elt == set->value) return true;
else if(elt < set->value) return find(set->left, elt);
else return find(set->right, elt);
}
}

Again, is this a faithful adaptation and will it work?


14. Add a print member fun tion to Set. Hint use re ursion: rst print the members in
the left subtree, then the value stored at the urrent node, and then the value in the
right subtree.
Abhiram Ranade, 2013. Do not distribute 385
Note: Your answer to the previous problem will likely print absolutely nothing for an
empty set. Suppose that you are to print a message \Empty set" in su h ases. Hint:
Use one non-re ursive member fun tion whi h alls a re ursive one.
15. Add a member fun tion with signature int smaller(int elt) whi h returns the num-
ber of elements in the set smaller than elt. Hint: Add a member ount to ea h node
whi h will indi ate the number of nodes in the subtree below that node. You will need
to update ount values suitably whenever you insert elements. Now use the ount
value to respond to smaller.
16. Experimentally verify Theorem 3. Let n denote the number of elements in the set.
Assume without loss of generality that the elements in the set are integers 1; 2; : : : ; n.
Run the insertion algorithm by generating numbers between 1 and n (without repla e-
ment) in random order. Measure the height of the resulting tree. Repeat 100 times
and take the average. Repeat for di erent values of n and plot average tree height
versus n.
Chapter 23

Inheritan e

Inheritan e is one of the most important notions in obje t oriented programming. The key
idea is: you an reate a lass B by designating it to be derived from another lass A. Created
this way, the lass B gets (\inherits") all the data members and ordinary fun tion members
of A. In addition to what is inherited, it is possible to in lude additional data and fun tion
members in B. It is also possible to rede ne some of the inherited fun tion members. The
lass B thus reated, is said to be a sub lass of the lass A. As you might suspe t, this is a
onvenient way to reate new lasses.
The most ommon and natural use of inheritan e is in the following setting. Suppose, a
program deals with ategories of obje ts, whi h are divided into sub ategories. For example,
a program might be on erned with bank a ounts, and these may be divided into di er-
ent types of a ounts, e.g. savings a ounts and urrent a ounts. Or a program might be
on erned with drawing geometri shapes on the s reen, and the ategory of shapes, as we
have seen, might be subdivided into sub ategories su h as ir les, lines, polygons and so on.
In su h ases it turns out to be useful to represent a ategory (e.g. a ounts or geometri
shapes) by a lass, and sub ategories (savings a ounts and urrent a ounts, or lines and ir-
les) by sub lasses. As you will note, the attributes asso iated with a ategory (e.g. a ount
balan e, or s reen position) are present in the sub ategories. Hen e it is natural that these
attributes will be de ned in the lass orresponding to the ategory. These attributes will be
inherited when we de ne sub lasses orresponding to the sub ategories. In ea h sub lass we
need additionally de ne the attributes whi h are spe i to the orresponding sub ategory.
For example, in the ir le sub lass we ould de ne the attributes enter and radius, while the
polygon lass will have verti es as the attributes. Categories and sub ategories are ommon
in real life, and hen e inheritan e an play a entral role in the design of omplex programs.
First some terminology. Suppose we derive a lass B from a lass A using inheritan e.
It is ustomary to say that lass B is a sub lass of lass A, is derived from A, or obtained
by extending lass A. And of ourse, B is said to inherit from A. It is likewise ustomary to
say that A is a super lass of B, or base lass of B or sometimes the parent lass of B. We an
have several lasses say B,C,D inheriting from A. In turn we may have lasses E,F inheriting
from B. In su h a ase, the lasses A, B, C, D, E, F are said to onstitute an inheritan e
heirar hy.
In this hapter we will mainly onsider the me hani s of inheritan e. We begin by on-
sidering a simple example and then dis uss how to use inheritan e in general. An important

386
Abhiram Ranade, 2013. Do not distribute 387
aspe t of inheritan e is that we an have many views of an obje t; sometime we might on-
sider it to be an instan e of a sub ategory (e.g. a ir le) at other times we may onsider it
as belonging to a ategory (e.g. a shape). In order to be able to shift views smoothly, we
need the notions of polymorphism and virtual fun tions. We dis uss these notions. In the
next hapter we onsider how to design programs using inheritan e.

23.1 Turtles with an odometer


Suppose we wish to design a lass mTurtle (short for metered turtle) whi h is exa tly like the
lass Turtle, ex ept that the turtle will keep a ount of how mu h distan e it has overed.
So a mTurtle will be able to move forward, turn, hange olours et . just like a Turtle, but
in addition it will have an additional member fun tion distan eCovered whi h will return
the total distan e overed till then.
Here is an example of a main program that we would like to write.
int main(){
initCanvas();
mTurtle m;
m.forward(100);
m.right(90);
m.forward(50);
out << m.distan eCovered() << endl;
}
This program should print 150.
23.1.1 Implementation using Composition
We rst onsider how mTurtle ould be implemented without inheritan e, using what you
already know. A simple idea is to ompose an mTurtle obje t by having a Turtle obje t as
a member. We will all this lass mTurtleC.
lass mTurtleC{ // Solution using omposition. (no inheritan e).
Turtle t;
double distan e;
publi :
mTurtleC(){
distan e = 0;
}
forward(double d){
distan e += abs(d); // be ause d may be negative.
t.forward(d);
}
double distan eCovered(){
return distan e;
}
Abhiram Ranade, 2013. Do not distribute 388
void right(double angle){
t.right(angle);
}
void left(double angle){
t.left(angle);
}
// similar forwarding ode for other fun tions allowed on Turtle..
};

As you an see, inside mTurtleC we have a Turtle obje t whi h you will see on the s reen,
and a member distan e whi h keeps tra k of how mu h the turtle has moved. Clearly,
when an mTurtleC is reated, we should set distan e to 0, whi h is what the onstru tor
above does. The onstru tor does not appear to do mu h with the turtle member t. But
you know that the member t is also reated, using the default Turtle onstru tor. Thus
a turtle will appears on the s reen. The member fun tion forward in mTurtleC auses
distan e to be updated, and auses the turtle to move as well. Finally, the member fun tion
distan eCovered prints distan e as expe ted.
The ode for right is simple, we just all the fun tion right on member t, with the
same argument. We will have to write su h forwarding fun tions for other fun tions su h as
left, hide and so on.
Clearly, this will enable us to write the main program given earlier; we merely have to
use mTurtleC in it instead of mTurtle. The solution is fairly satisfa tory, the main drawba k
is the need to write the forwarding fun tions.
23.1.2 Implementation using Inheritan e
Using inheritan e, we an de ne a metered turtle more ompa tly, as follows. We will all
this lass mTurtleI.
lass mTurtleI : publi Turtle{ // solution with inheritan e
float distan e;
publi :
mTurtleI(){
distan e = 0;
}
void forward(float d){
distan e += abs(d);
Turtle::forward(d);
}
float distan eCovered(){
return distan e;
}
};

We will shortly explain what ea h line in this does. For now we merely note that this will
essentially do what the ode in Se tion 23.1.1 did. With this, we will be able to run the
Abhiram Ranade, 2013. Do not distribute 389
main program given at the beginning of Se tion 23.1, of ourse we will need to use mTurtleI
in the main program instead of mTurtle.
Note that we have not de ned fun tions su h as right. We have not expli itly de ned
the member t of type Turtle. As we will see next, these are inherited!

23.2 General prin iples


In general we an de ne a lass B as a sub lass of an existing lass A, by writing:
lass B : type-of-inheritan e A {
// body des ribes how B is different from A
}
In this, type-of-inheritan e an either be publi , private or prote ted. We begin our
dis ussion with publi inheritan e, whi h was used in our lass mTurtleI in the previous
se tion. We will dis uss other types of inheritan e in Se tion 23.7.
Note that the name A must itself already have been de ned when we de ne B. This is
typi ally a omplished by in luding the header le of A.
The above de nition will reate a lass B whi h starts o with all data members and
fun tion members of A, ex ept for the onstru tors and the destru tor. If we want B to have
some additional data or fun tion members, we de ne them in the body. We an also rede ne
some fun tions that were present in A { the new de nitions will be used for obje ts of lass
B. We dis uss the details next.
As we have said, the data members present in A will also appear in the obje ts of lass
B. They will appear individually, i.e. we will be able to a ess them dire tly as per some
rules that we dis uss soon. However, we an also think that the inherited members together
onstitute an inherited obje t of lass A inside ea h obje t of lass B. In addition, we an have
new data members, by de ning them in the body of the de nition of lass B.
Thus for our lass mTurtleI of Se tion 23.1.2 we will get the inherited obje t and the
new data member distan e. As you may guess, a Turtle obje t will ontain many data
members, for example a member olor (of type Color) whi h holds information about the
olour of the turtle. These would be in luded in of mTurtleI. Figure 23.1(a) shows the
ontents of the obje t produ ed for the lass mTurtleI. For omparison, in Figure 23.1(b),
we have also shown the ontents of an obje t of type mTurtleC as well. An obje t of lass
mTurtleC has two data members, a member distan e whi h is a double and a member t
whi h is a Turtle. Thus both obje ts of Figure 23.1 really ontain the same information.
The main di eren e is that in mTurtleC the members of the ontained turtle obje t t su h as
olor are not dire tly a essible, whereas in mTurtleI, these members are dire tly a essible.
All the member fun tions in lass A, ex ept for the onstru tors and destru tor are as-
sumed present in B. These fun tions will refer to members of A, but this will not ause a
problem be ause these members are also inherited. The body of the de nition an also
ontain additional member fun tions that are only meant for B. The body may also ontain
rede nitions of inherited member fun tions. For example, suppose the body ontains a def-
inition of f, whi h is an inherited member fun tion, i.e. a fun tion already de ned in A. In
su h a ase, the new de nition is to be used with instan es of B. The new de nition is said
Abhiram Ranade, 2013. Do not distribute 390

color : Color t : Turtle


..other members "Inherited object"
inherited from
Turtle.. distance : double

distance : double

(a) mTurtleI object (b) mTurtleC object

Figure 23.1: Contents of obje ts of lass mTurtleI and lass mTurtleC

to override the old de nition, and will be used for obje ts of lass B. The de nition of f from
A will ontinue to be used for obje ts of lass A. Instan es of lass B an also use the old
de nition from A if ne essary. Only, to do that, a slightly involved syntax is needed. Instead
of just using the name f of the fun tion, we must write A::f.
We have seen examples of all this in the de nition of mTurtleI in Se tion 23.1.2. We
de ned a new member fun tion distan eCovered, whi h is not present in the super lass
Turtle, but is spe ial to the lass mTurtleI. We also rede ned the member fun tion forward
present in Turtle. The new fun tion hanges the distan e member appropriately, and also
alls the fun tion forward in lass Turtle, using the syntax Turtle::forward. You an
onsider this fun tion as being alled on the inherited Turtle obje t inside mTurtleI.
Note that although obje ts of lass B inherit all data members of A, their a essibility
is limited. In fa t, the a essibility of the inherited fun tion members is also limited. We
dis uss the pre ise rules for this next.
23.2.1 A ess rules and prote ted members
Suppose that m is a data or fun tion member of A and b is an instan e of B, a sub lass of A.
Then the manner in whi h the member m of instan e b an be a essed is determined by the
following rules.
Case 1: m is a publi member of A: In this ase, we an onsider m to be a publi member
of B as well. In other words, m an be a essed inside the de nition of B, as well as
outside the de nition of B.
Case 2: m is a private member of A: Then m annot be a essed in the ode that we
write inside the de nition of B. And of ourse it annot be a essed outside. In other
words, private members are a essible only inside the de nition of the lass in whi h the
member was de ned (and its friend lasses). The sub lass instan es annot dire tly
a ess private members of the super lass. This is not to say that private members
of the super lass are useless. There might well be a publi or prote ted (see below)
Abhiram Ranade, 2013. Do not distribute 391
member fun tion f of A whi h refers to m. Now, the ode in B an refer to f, and hen e
it will indire tly refer to m.
Case 3: m is a \prote ted" member of A: The notion of prote ted is as follows. If a
member of a lass A is designated as prote ted then it an be a essed only inside
the de nition of A or of its sub lasses. In other words, a prote ted member is less
a essible than a publi member (whi h is a essible everywhere), and more a essible
than a private member, (whi h is a essible only in the de nition of A). Note that m is
to be onsidered a prote ted member of B as well.
We illustrate the above rules using the following ode snippet.
lass A{
private:
int p;
prote ted:
int q;
int getp(){return p;}
publi :
int r;
void init(){p=1; q=2; r=3;}
};

lass B: publi A{
double s;
publi :
void print(){
out << p << endl; // ompiler error 1. p is private.
out << q << ", "
<< r << ", "
<< getp() << endl;
}
};

int main(){
B b;
b.init();
out << b.p // ompiler error 2. p is private
<< b.q // ompiler error 3. q is prote ted
<< b.r
<< b.getp() // ompiler error 4. getp is prote ted.
<< endl;
b.print();
}
If you ompile this ode, you will get the 4 ompiler errors as marked. Compiler errors
1 and 2 are be ause p is private in A, and an hen e not be a essed in the de nition of B,
Abhiram Ranade, 2013. Do not distribute 392

p : int p : int
q : int q : int
r : int r : int
Inherited object
s : double

(a) A object (b) B object

Figure 23.2: Contents of obje ts of lass A and lass B

or in main. Compiler errors 3 and 4 are be ause q and getp are prote ted in A, and hen e
annot be used outside of the de nition of A or of any sub lass of A. Indeed you will see that
prote ted members q and getp() an be used ne inside the de nition of B. Further, the
publi members init, and r an be used if needed in both B as well as main.
On e the o ending parts are removed, the ode will ompile ne. On exe ution, the print
statement in main will print 3, and the statement b.print() will print 2,3,1.
Figure 23.2 shows the ontents of the obje ts of lasses A and B. Note that all data
members from A are present in obje ts of lass B, even if they might not be dire tly a essible.
23.2.2 Constru tors
Suppose lass B is a sub lass of lass A. A onstru tor for B an to be de ned using the
following general form.
B( onstru tor-arguments) : all-to- onstru tor-of-A, initialization-list
{
body
}
When you all the onstru tor for B, the all-to- onstru tor-of-A is rst alled, and this
onstru ts the inherited obje t (of lass A) ontained inside the instan e of B being reated.
The initialization-list has the form as in Se tion 16.1.5, and is used to initialize the
new members of B. After that, body is exe uted. The part
: all-to- onstru tor-of-A
is optional. If it is omitted, the default onstru tor of A gets alled. The initialization-list
is also optional, and alternatively, the new members ould be initialized inside body.
In Se tion 23.1 you saw an example in whi h the default onstru tor of Turtle got used
for reating a mTurtleI. Suppose now that we had an alternate onstru tor for Turtle
whi h took arguments x,y giving the initial position for the turtle. Then we ould write an
alternate onstru tor for mTurtleI as follows.
Abhiram Ranade, 2013. Do not distribute 393
mTurtleI(double x, double y) : Turtle(x,y), distan e(0) {}
With this onstru tor, the metered turtle would be reated at position (x,y) on the s reen,
and the new member distan e would be initialized to 0 using the initialization list. The
body of the onstru tor would then be left empty.
23.2.3 Destru tors
As before suppose we have a lass B whi h inherits from lass A. Then the destru tor for lass
B should be used to destroy the new data members introdu ed in B that were not present in
A. The data members inherited from A? These would be destroyed by an impli it all that
would get made to the destru tor of A at the end of the exe ution of the all to the destru tor
of B. You should not expli itly make a all to the destru tor of A from inside the destru tor
of B!
The general rule is: destru tion happens automati ally, in reverse order of reation. In
the exer ises you will experiment with ode whi h will illustrate these ideas.
23.2.4 Basi operations on sub lass obje ts
A sub lass is a lass, so all operations allowed on obje ts of lasses are allowed on obje ts
of sub lasses, and work similarly. For example, obje ts an be opied, passed to fun tions,
and so on, as dis ussed in Chapter 15.
23.2.5 The type of a sub lass obje t
We have said that a lass is a type, i.e. an obje t of lass A has type A. Suppose B is a
sub lass of lass A. Then a key idea in inheritan e is: obje ts of lass B an be onsidered to
have type B as well as type A. This idea turns out to be quite useful.
The following analogy might be useful to understand this. Consider the ategory of
owers, in whi h we have sub ategories su h as roses, lotuses and so on. So if someone has
demanded owers, we an give roses. In other words, a spe i rose obje t is useful as a rose
as well as as a ower.
23.2.6 Assignments mixing super lass and sub lass obje ts
If an obje t an be onsidered to be of the type of its super lass, we should allow an obje t of
a sub lass to be assigned to variable of the super lass. This is indeed possible. Note however
that the sub lass might have some additional data members. In su h a ase, the additional
members are dropped, or sli ed o , during the assignment.
You an also assign the address of a sub lass obje t into a pointer variable of the super-
lass.
Figure 23.3 shows some examples. First we have tha assignment a = b. Sin e b has an
extra attribute y, during the assignment this will be sli ed o , and only the attribute x will
get opied. Thus the rst print statement will print 2, the value that got opied.
Next we have aptr = &b, whi h stores the address of the lass B obje t b into the pointer
variable aptr of type A*. As we said, this is allowed, sin e A is a super lass of B. The next
Abhiram Ranade, 2013. Do not distribute 394

lass A{
publi :
int x;
A(){ x = 1; }
void f(){ out <<"Calling f of A.\n";}
};
lass B: publi A{
publi :
int y;
B(){ x = 2; y = 1;}
void f(){ out <<"Calling f of B.\n";}
};

int main(){
A a, *aptr;
B b, *bptr;

a = b; // member y will be sli ed off


// member x will be opied.
out << a.x << endl; // prints 2;

aptr = &b; // assigning sub lass obje t to super lass pointer


out << aptr->x << endl; // prints 2;
aptr->f();

A& aref = b; // referen e of type A to variable of type B.


aref.f();
}

Figure 23.3: Assignments mixing sub lass and super lass


Abhiram Ranade, 2013. Do not distribute 395
statements use aptr. In the rst, we a ess the member x, using the standard syntax
aptr->x, and this will print 2 as expe ted. In the next statement, aptr->f(), we have
invoked the member fun tion f. Here there is some possible onfusion: will this mean the f
de ned in A or the f de ned in B? The default answer is that sin e aptr is of type pointer
to A, the members from A will be used. Thus, this will print the message "Calling f of A.".
If you are unhappy with this default, hold on till Se tion 23.3.
Note that in the above ode, we annot assign an obje t of the super lass into a variable
of the sub lass, i.e. write something like b = a;. The intuition behind this, going to our
ower example, is as follows. Wherever a ower is expe ted, you an supply a rose; however,
if a rose is expe ted, you annot supply an arbitrary ower. Likewise, it is in orre t to write
bptr = &a as well.
Finally, we an reate referen es of the type super lass to obje ts of the sub lass. This is
done at the end of Figure 23.3. Indeed even in this ase the fun tion f in A will be invoked.

23.3 Polymorphism and virtual fun tions


Consider the ode of Figure 23.3. As we dis ussed above, the all aptr->f() will ause the
fun tion f in lass A to be used. But you might say: aptr really points to an obje t of type
B so isnt it more useful if the f in B were used? You an make this happen by de laring f to
be a virtual fun tion. For this, you simply add the keyword virtual before the de nition of
f in A. Thus the de nition of A would have to be:
lass A{
publi :
int x;
A(){ x = 1; }
virtual void f(){ out <<"Calling f of A.\n";}
};
The keyword virtual says that the de nition of f should not be treated as a unique, nal
de nition. It is possible that f might be over-ridden in a sub lass, and if so, that de nition
of f whi h is most appropriate (most derived!) for the obje t on whi h the all is made
should be onsidered. When we all aptr->f(), the most appropriate de nition for f is the
one in B, sin e aptr a tually points to an obje t of type B. So that de nition gets used, and
our ode will now indeed print "Calling f of B.".
Note further that if f is virtual, its most derived version will get used if it is invoked on
a referen e as well. Thus the last statement of Figure 23.3 will also ause f from B to be
invoked.
Here is a more subtle example of the same idea.
lass Flower{
publi :
void whoAmI(){ out << name() << endl; }
virtual string name(){ return "Flower"; }
};
Abhiram Ranade, 2013. Do not distribute 396
lass Rose: publi Flower{
publi :
string name(){ return "Rose"; }
};

int main(){
Flower a;
Rose b;
a.whoAmI();
b.whoAmI();
}
Exe uting a.whoAmI() will learly ause \Flower" to be printed out. More interesting is
the exe ution of b.whoAmI(). What should it print? The all b.whoAmI() is to the inherited
member fun tion whoAmI in the super lass Flower. That fun tion whoAmI alls name, but
the question is whi h name. Will it be the name in Flower or in Rose? The answer turns out
to be the name in Rose, be ause (a) the obje t on whi h whoAmI is alled is of type Rose,
and (b) name is virtual. Thus the most derived de nition of name appropriate for the obje t
on whi h it is invoked will be used. Sin e the obje t on whi h it is invoked is of type Rose,
the name from that lass will be used. Thus the last statement will print ``Rose''. Note
that had we not used virtual, both statements would have printed ``Flower''.
In this example, the all name() inside the member fun tion whoAmI is said to be poly-
morphi , be ause the same all will either ause the fun tion in Flower to be alled, or the
fun tion in Rose to be alled, depending upon the a tual type of the obje t on whi h it is
invoked. Note that the a tual type will only be known during exe ution.
Likewise the alls aptr->f() and aref.f() in Figure 23.3 would be polymorphi if f is
de lared virtual.
23.3.1 Virtual Destru tor
Suppose aptr is of type A*, and points to some obje t. Suppose we wish to release the
memory. So we write delete aptr;. This will all the destru tor, but the question again
is, whi h destru tor? By default, the destru tor of A will be alled. However, if the obje t
pointed to by aptr is of type B, whi h is a sub lass of A, then learly we should be alling the
destru tor for B. We an for e this to happen by de laring the destru tor of A to be virtual.
Indeed, whenever we expe t a lass to be extended, it is a good idea to de lare its destru tor
to be virtual.
Here is an example.
lass A{
publi :
virtual ~A(){ out <<"~A.\n";}
};
lass B: publi A{
int *z;
publi :
Abhiram Ranade, 2013. Do not distribute 397
B(){z = new int;}
~B(){
out <<"~B.\n";
delete z;
}
};

int main(){
A* aptr;
aptr = new B;
delete aptr;
}
If we do not de lare the destru tor of A to be virtual, then after the operation delete aptr;
in the main program, the memory allo ated for z will not be freed. However, sin e we have
de lared the destru tor of A to be virtual, the destru tor of B will be alled when delete
aptr; is exe uted, instead of the destru tor of A. Thus the the operation delete z; will
take pla e. Of ourse, as always the destru tor of A will also be alled, sin e our rule is
that the destru tor of the super lass will be alled after the destru tor of the sub lass. Do
ompile and exe ute this ode, you will see from the message what is alled. Remove the
keyword virtual and exe ute again, you will see that only the destru tor of A is alled.

23.4 Program to print past tense


Suppose you wish to write a program that takes as input a verb from the English language,
and prints out its past tense. Thus, given \play", the program must print \played", given
\write", the program must print \wrote", and so on. A simple implementation would be to
store every verb and its past tense as strings in memory. Given the verb, we an then print
out the orresponding past tense.
But you will perhaps observe that for most verbs, the past tense is obtained simply by
adding a suÆx \ed", as is the ase for the verbs \play", \walk", \look". We may onsider
these verbs to be regular. Verbs su h as \be", \speak", \eat" whi h do not follow this rule
ould be onsidered irregular. Thus it makes sense to store the past tense form expli itly
only for irregular verbs; for regular verbs we ould simply atta h \ed" when asked. This
an be programmed quite ni ely using inheritan e.
We de ne a lass verb that represents all verbs; it onsists of sub lasses regular and
irregular respe tively. The de nition of verb ontains information whi h is ommon to
all verbs. The de nition of regular adds in the extra information needed for regular verbs,
and similarly the de nition of irregular.
lass verb{
prote ted:
string root;
publi :
string getRoot(){return root;}
Abhiram Ranade, 2013. Do not distribute 398
virtual string past_tense(){return ""};
};

The member root will store the verb itself. We have de ned the member fun tion past tense
to be virtual. For now it returns the empty string. But this is not important, sin e we expe t
to override it in the sub lasses.
The sub lasses regular and irregular are as you might expe t.
lass regular : publi verb{
publi :
regular(string rt){
root = rt;
}
string past_tense(){return root + "ed";}
};

lass irregular : publi verb{


string pt; // past tense of the verb
publi :
irregular(string rt, string p){
root = rt;
pt = p;
}
string past_tense(){return pt;}
};
Thus, to reate an instan e v1 that represents the verb \play" we would just write
regular v1("play");
After this if we wrote v1.past tense(), we would get the string "played" as the result.
Similarly
irregular v2("be","was");

would reate an instan e v2 to represent the verb \be". And of ourse v2.past tense()
would return \was".
We now see how the above de nitions an be used to write a main program that returns
the past tense of verbs. Clearly, we will need to somehow store the information about verbs.
For this, we use a ve tor. We annot have a single ve tor storing both regular and irregular
verbs. However, we an de ne a ve tor of pointers to verb in whi h we an store pointers
to irregular as well as regular obje ts. Thus the program is as follows.
int main(){
ve tor<verb*> V;
V.push_ba k(new regular("wat h"));
V.push_ba k(new regular("play"));
V.push_ba k(new irregular("go","went"));
Abhiram Ranade, 2013. Do not distribute 399
V.push_ba k(new irregular("be","was"));

string query;
while( in >> query){
size_t i;
for(i=0; i<V.size(); i++)
if (V[i℄->getRoot() == query){
out << V[i℄->past_tense() << endl;
break;
}
if(i == V.size()) out << "Not found.\n";
}
}
We begin by reating the ve tor V. We then reate instan es of regular and irregular verbs
on the heap, and store pointers to them in onse utive elements of V. Finally, we enter a
loop in whi h we read in a query from the user, he k if it is present in our ve tor V. If so,
we print its past tense. Note that if the for loop ends with i taking the value V.size(), it
must be the ase that no entry in V had its root equal to the query. In this ase we print
"Not found.". As you know, the while loop will terminate when in ends, e.g. if the user
types ontrol-d.
A number of points are to be noted regarding the use of inheritan e in this example.
1. Our need was to represent the ategory of verbs whi h onsisted of mutually disjoint
sub- ategories of irregular and regular verbs. This is a very standard situation in whi h
inheritan e an be used.
2. The ve tor V is polymorphi : it an ontain pointers to obje ts of type irregular as
well as of type regular. We an invoke the operation past tense on obje ts pointed
to by elements of V, without worrying about whether the obje ts are of type regular
or irregular. Be ause past tense is virtual, the orre t ode gets exe uted.

23.5 Abstra t Classes


You will note that we return the empty string in the past tense fun tion in verb. Returning
an empty string does not make sense, but we did this be ause we expe ted that the verb
lass would never be used dire tly; only its sub lasses would be used in whi h the fun tion
would get overridden. This idea works, but it is not aestheti ally pleasing that we should
need to supply an implementation of past tense in verb expe ting fully well that it will
not get used.
One possibility is to only de lare the member fun tion past tense in verb, and not
supply any implementation at all. Unfortunately, whenever an implementation is not sup-
plied, the ompiler expe ts to nd it somewhere, in some other le perhaps. If su h an
implementation is not given the ompiler or the linker will produ e an error message.
Abhiram Ranade, 2013. Do not distribute 400
What we need is a way to tell the ompiler that we do not at all intend to supply an
implementation of past tense for the verb lass. This is done by suÆxing the phrase \=
0" following the de laration. Thus we would write
lass verb{
...
publi :
virtual string past_tense() = 0;
...
}
Writing \= 0" following the de laration of a member fun tion tells the ompiler that we do
not intend to at all supply an implementation for the fun tion. You may think of 0 as rep-
resenting the NULL pointer, and hen e e e tively indi ating that there is no implementation.
There is an important onsequen e to assigning a fun tion to 0. Suppose a lass A
ontains a member fun tion f assigned to 0. Then we annot reate an instan e of A! This is
be ause for that instan e we would not know how to apply the fun tion f. In C++, lasses
whi h annot be instantiated are said to be abstra t. Indeed, the only way of making a lass
abstra t is to assign one of its member fun tions to 0. 1

So in our ase, if we assign past tense to 0 in verb, then the lass verb would be ome
abstra t. We would not be able to reate instan es of it. But this is ne, we indeed would
not like users to instantiate verb, instead we expe t them to instantiate either regular or
irregular.

23.6 Multiple inheritan e


Sometimes, an obje t an be thought of as a spe ialization of not one, but two other obje ts.
For example, we might have an Automobile lass and a SolarPoweredDevi e lass.
lass Automobile{
double mileage;
};
lass SolarPoweredDevi e{
double ellEffi ien y;
};
Suppose we also need to represent solar powered automobiles, they would need to have
features of both the Automobile lass as well as SolarPoweredDevi e lass. We an get
this by onstru ting a lass SolarPoweredAutomobile whi h inherits from both!
lass SolarPoweredAutomobile : publi Automobile,
publi SolarPoweredDevi e {};
If we make the onstru tor of a lass private and there are no member fun tions that use the onstru tor,
1
then e e tively we have ensured that the lass annot be instantiated. But te hni ally su h lasses are not
onsidered to be abstra t.
Abhiram Ranade, 2013. Do not distribute 401
GP

P1 P2

Figure 23.4: Diamond inheritan e. Arrows go from hild to parent.


Now instan es of the SolarPoweredAutomibile lass would have members mileage as well
as ellEffi ien y, as you might expe t. Fun tion members would also be inherited from
all the super lasses, as many as there might be.
There are some obvious problems: what happens if the parent lasses P1, P2 of a lass
C both have a member with the same name m? In this ase, the hild lass would get two
opies of the member, and you would have to refer to the opies as P1::m and P2::m.
23.6.1 Diamond Inheritan e
Suppose the parents P1, P2 of some lass C themselves inherit from a ommon base lass GP,
as shown in Figure 23.4. In this ase, the lass C will a tually get two opies of the inherited
obje t GP, orresponding to P1 and P2.
This ase, in whi h we derive a lass C by inheriting from parent lasses P1, P2, whi h in
turn inherit from a single lass GP is said to onstitute Diamond inheritan e. This is be ause
the pi torial representation of the inheritan e has the diamond shape, Figure 23.4.
However, sometimes when we have diamond inheritan e, we might want to have only one
opy of the inherited obje t instead of one from ea h parent. It is possible to do this in C++
by spe ifying the derivation of P1, P2 from GP as virtual. Thus we would write:
lass GP{ double x; };
lass P1: virtual publi GP{};
lass P2: virtual pubil GP{};
lass C: publi P1, publi P2{};
With this, the lass C will ontain only one opy of the inherited obje t GP. Note that this
inherited obje t will be initialized dire tly by alling its onstru tor. Thus if the initialization
list of P1 or P2 ontains a all to the onstru tor of GP, then those alls will be ignored.

23.7 Types of inheritan e


So far we have only dis ussed publi inheritan e. C++ allows other kinds of inheritan e
also, namely prote ted inheritan e and private inheritan e.
If a lass B inherits from a lass A using prote ted inheritan e, then the publi and
prote ted members of A be ome prote ted members of B.
Abhiram Ranade, 2013. Do not distribute 402
If a lass B inherits from a lass A using private inheritan e, then the publi and prote ted
members of A be ome private members of B.
As you an see, prote ted and private inheritan e progressively restri t the a essibility
of the members inherited into the derived lass. These kinds of inheritan e appear to be
used mu h less in pra ti e. So we will not dis uss them any further.

23.8 Remarks
Inheritan e is a powerful idea. However, like any powerful idea, it needs to be used with
are.
An informal rule of thumb is as follows. Suppose A; B are entities whi h you wish to
represent using lasses A,B. If entities of type B are spe ialized versions of type A, then
inherit lass B from lass A. Informally, you may ask, do the entities B; A have an \is-a"
relationship? Clearly, a rose is a ower, so the entities rose, ower have an \is-a" relationship.
So in this ase, use inheritan e. If two entities have a \has-a" relationship, then better use
omposition. For example, owers have petals, so the entities ower, petal have a \has-a"
relationship. It is best to model this relationship by omposition, i.e. by making a petal a
member inside a ower.
An important advantage of inheritan e is polymorphism. As we saw in Se tion 23.4,
we might have several sublasses of a base lass. We an onveniently store instan es of
the sub lasses in a ve tor (or some other olle tion), for this we an onsider them to be
members of the base lass. But we an invoke fun tions on the obje ts, and if the fun tions
are virtual, we get the bene t of onsidering them to be members of the sub lasses too. This
ame in handy when writing the program to display past tense of verbs. And we will see
more examples of this in the next hapter.

23.9 Exer ises


1. Suppose you have a lass V de ned as
lass V{
prote ted:
double x,y,z;
publi
V3(double p, double q, double r){ x=p; y=q; z=r; }
}

De ne a lass W that inherits from V and has a member fun tion dot whi h omputes
the dot produ t of two ve tors. Thus given V type obje ts v,w, then the dot produ t is
v.x * w.x + v.y * w.y + v.z * w.z. Be areful that you only use the onstru tor
provided in V.
2. De ne a lass realTurtle su h that realTurtle obje ts move with some spe i able
speed when they move. They should also turn slowly.
Abhiram Ranade, 2013. Do not distribute 403
3. What do you think will happen when you exe ute the program given below? Run it
and he k if you are right.
lass A{
publi :
A(){ out << "Constru tor(A).\n";}
~A(){ out << "Destru tor(A).\n";}
};

lass B: publi A{
publi :
B(){ out << "Constru tor(B).\n";}
~B(){ out << "Destru tor(B).\n";}
};

lass C: publi B{
publi :
C(){ out << "Constru tor(C).\n";}
~C(){ out << "Destru tor(C).\n";}
};

int main(){
C ;
}

4. What will the following ode print?


stru t A{
virtual int f(){return 1;}
int g(){return 2;}
};

stru t B : publi A{
int f(){return 3;}
int g(){return 4;}
}

A* aptr;
aptr = new B;
out << aptr->f() <<' '<< aptr->g() << endl;

5. Write the past tense generation program using just two lasses, a verb lass and an
irregular lass. A regular verb should be reated as an instan e of verb, and an
irregular as an instan e of irregular.
Abhiram Ranade, 2013. Do not distribute 404
6. You might note that the past tense of several verbs ending in \e" is obtained by adding
\d", e.g. re ite, advise. Add an extra sub lass to the verb lass to store the past tense
of su h verbs ompa tly.
Chapter 24

Inheritan e based design

Inheritan e is often very useful in designing large omplex programs. Its rst advantage
we have already dis ussed: inheritan e is onvenient in representing ategories and sub at-
egories. But there are some related advantages whi h have to do with the management of
the program development pro ess. We will dis uss these next, and then in the rest of the
hapter we will see some examples.
There are many approa hes to designing a large program. A lassi al approa h requires
that we rst make a omplete study of the program requirements, and only thereafter start
writing the program. More modern approa hes instead a knowledge/allow for the possibility
that requirements may not be understood unless one has built a few versions of the program.
Also, if a program works beautifully, users will inevitably ask that it be enhan ed with more
features. In any ase, programs will have a long lifetime in whi h the requirements will
evolve. So the modern approa hes stress the need to design programs su h that it is easy to
hange them. As we have dis ussed, the whole point of inheritan e is to build new lasses
out of old, and this idea will surely ome in useful when requirements hange.
Even if the requirements are well understood and xed (at least for that time in the
program development pro ess), designing a large program is tri ky. It greatly helps if the
program an be designed as a olle tion of mostly independent fun tions or lasses whi h
intera t with ea h other in a limited, learly de ned manner. Su h partitioning is helpful
in understanding the behaviour of the program and also he king that it is orre t: we an
onsider testing the parts separately for example. But it also has another advantage: di erent
programmers an work on the di erent parts simultaneously. As we will see, inheritan e
based designs have mu h to o er in this regard also.
Another modern programming trend is the use of omponents. Most likely, to write
professional programs you will not use bare C++ (or any other programming language), but
will start from a olle tion of fun tions and lasses whi h have been already built by others
(for use in other, similar proje ts). You will adapt the lasses for your use, and as we have
seen, this adaptation is natural with inheritan e.
In the rest of this hapter we will see two ase studies. First we revisit our formula
drawing program. We will rewrite it using inheritan e. It will turn out that this way of
writing makes it easier to maintain and extend. Next we will dis uss the design of the
graphi s in simple pp. Inheritan e plays a substantial role in its design. Finally, we will see
the omposite lass, whi h will enable you to de ne new graphi al obje ts whi h are made

405
Abhiram Ranade, 2013. Do not distribute 406
by omposing the simple graphi s obje ts we know so far.

24.1 Formula drawing revisited


Consider the formula drawing problem from Se tion 22.1: given a mathemati al formula,
draw it on the graphi s anvas in a ni e manner. In Se tion 22.1 our spe i goal was
to draw the formula su h that operands in sums, di eren es and produ ts were drawn left
to right horizontally, while the dividend and the divisor were drawn above and below a
horizontal bar respe tively. In this se tion we will see how the program an written in using
inheritan e. A bene t of this will be that it will be easy to extend the program to in lude new
operators. To illustrate this we will implement the exponentiation operator whi h requires
the exponent to be written above and to the right of the base.
For simpli ity, we ignore the problem of a epting input from the keyboard: wea will
assume that the formula to be drawn is given as a part of the program, i.e. to draw b we
will rst onstru t it in our program by writing something like:
+

Node f2('/', new Node("a"),


new Node('+', new Node("b"), new Node(" "))
);
and then we an all f2.setSize() and so on.
24.1.1 Basi design
The use of inheritan e is natural if the entities we want to represent form a ategory and
sub ategories thereof. In the present ase, we wish to represent mathemati al formulae.
These formulae an further be lassi ed based on the top level operators: for example in
the formula b a , the last operation to be performed is division, and hen e we will designate
it to be of the sub ategory DIV. In the formula a + b , the last operation to be performed
+

is addition, so we will designate it to be of the sub ategory SUM. So we have the general
ategory of mathemati al formulae, and sub ategories SUM, DIFF, DIV, PROD, based on
the last operation performed to evaluate the formula.
We will use the lass Formula to represent all mathemati al formulae. This will be
analogous to the lass Node of Se tion 22.1.3. This lass will have a sub lass Formula2
whi h will represent all mathemati al formulae in whi h the top level operator is binary.
This lass will have sub lasses Sum, Diff, Prod and Div respe tively representing formulae
in whi h the top level operators are +, -, , and . Remember, that in the Exer ises of
Chapter 22 we pointed out that it helps to onsider unary and ternary formulae { you an
think of the lass Formula2 as stri tly ontained in Formula.
The algorithm for drawing the formula will be the same; hen e we will have methods
setSize and draw in all lasses. These will be de ned di erently depending upon the type
of the operator.
Here is the de nition of the lass Formula.
lass Formula{
prote ted:
Abhiram Ranade, 2013. Do not distribute 407
double width, height, des ent;
publi :
virtual void setSize()=0;
virtual void draw(float lx, float ly)=0;
double getWidth(){return width;}
double getHeight(){return height;}
double getDes ent(){return des ent;}
};

We do not expe t Formula to be instantiated, so we have de lared some of its methods to


be pure virtual. Also note that in Se tion 22.1.3, we used stru tures instead of lasses. Thus
everything was publi . Now we are more areful about making members visible and hen e
we have de ned a essor fun tions for width, height and des ent.
We next de ne the lass of formulae with 2 operands at the top level.
lass Formula2 : publi Formula{
prote ted:
Formula* lhs;
Formula* rhs;
virtual string op()=0;
};
Instead of storing the operator expli itly, we are using a fun tion op whi h will return it.
The fun tion will be de ned only in lasses in whi h the operator is known.
Next we de ne the sub lass Formula2h of expressions whi h require a horizontal layout.
lass Formula2h : publi Formula2{
publi :
void setSize(){
lhs->setSize();
rhs->setSize();
des ent = max(lhs->getDes ent(), rhs->getDes ent());
width = lhs->getWidth() + textWidth(op()) + rhs->getWidth();
height = des ent + max(lhs->getHeight() - lhs->getDes ent(),
rhs->getHeight() - rhs->getDes ent());
}
void draw(float lx, float ly){
lhs->draw( lx, ly);
rhs->draw( lx+lhs->getWidth()+textWidth(op()), ly);
Text( lx+lhs->getWidth()+textWidth(op())/2, ly, op()).imprint();
}
};
These fun tion implementations are similar to the ase '+' of the orresponding fun tions on
Node(Se tion ??). The only di eren e is that we are using a essor fun tions instead of the
members height, width, des ent and op is not a data member but a fun tion member.
We an now reate lasses to represent sums, di eren es, and produ ts.
Abhiram Ranade, 2013. Do not distribute 408
lass Sum : publi Formula2h{
publi :
Sum(Formula* lhs1, Formula* rhs1){ lhs = lhs1; rhs = rhs1; }
string op(){ return "+";}
};

lass Diff : publi Formula2h{


publi :
Diff(Formula* lhs1, Formula* rhs1){ lhs = lhs1; rhs = rhs1; }
string op(){ return "-";}
};

lass Prod : publi Formula2h{


publi :
Prod(Formula* lhs1, Formula* rhs1){ lhs = lhs1; rhs = rhs1; }
string op(){ return "*";}
};
These lasses merely give a onstru tor, and the operator. Noti e that the layout aspe ts
have been dealt with in the lass Formula2h.
We ould analogously de ne an Formula2v lass, whi h does verti al layout of its operands.
However, it is unlikely there will be many operators requiring a verti al layout with a sepa-
rating horizontal bar. So we dire tly de ne the Div lass.
lass Div : publi Formula2{
stati onst float Bheight = 20; //spa e for horizontal bar.
publi :
Div(Formula* lhs1, Formula* rhs1){ lhs = lhs1; rhs = rhs1; }
string op(){return "/";}
void draw(float lx, float ly){
Line( lx, ly, lx+width, ly).imprint();
lhs->draw( lx+width/2-lhs->getWidth()/2, ly-Bheight/2-lhs->getDes ent());
rhs->draw( lx+width/2-rhs->getWidth()/2, ly+
Bheight/2+rhs->getHeight()-rhs->getDes ent());
}
void setSize(){
lhs->setSize(); rhs->setSize();
width = max(lhs->getWidth(), rhs->getWidth());
height = lhs->getHeight() + Bheight + rhs->getHeight();
des ent = rhs->getHeight() + Bheight/2;
}
};
This orresponds to the ode for the ase '/' in the orresponding fun tions on Node (Se -
tion ??). It also de nes a onstru tor and the fun tion op.
Finally, we need a lass to represent literals, i.e. numbers or variables given in the
formula.
Abhiram Ranade, 2013. Do not distribute 409
lass Literal : publi Formula{
string value;
publi :
Literal(string v){value=v;}
void setSize(){
width = textWidth(value);
height = textHeight(); des ent = height/2;
}
void draw(float lx, float ly){
Text( lx+width/2, ly,value).imprint();
}
};
This orresponds to the ode for the ase 'P' in the orresponding fun tions on Node (Se -
tion ??).
We an now give a simple main program whi h an use the above de nitions to render
the formula 1 + 2
.
451 +35
5

int main(){
initCanvas("Formula drawing");

Sum e(new Literal("1"),


new Div(new Literal("2"),
new Sum(new Div(new Literal("451"),new Literal("5")),
new Literal("35"))));

e.setSize();
e.draw(200,200+e.getHeight()-e.getDes ent());

getCli k();
}

24.1.2 Comparison of the two approa hes


At rst glan e, it might seem that the inheritan e based approa h is more verbose than the
approa h of Se tion 22.1. This is true, but the verbosity has bought us many things.
A key improvement is that we have partitioned the program into manageable pie es. The
ode of Se tion 22.1 had just one lass. All the omplexity was pla ed into that lass. In
ontrast, in the new ode, di erent on erns are separated into di erent lasses. For example,
the lass Formula2 only models the fa t that formulae an have two operands, nothing more.
The lass Formula2h shows how to layout formulae requiring horizontal layout. We an pla e
ea h lass into its header and implementation les, and the main program into a separate
le, if we wish. This way, if we wish to hange something regarding a ertain issue (e.g.
horizontal layout) we know that we will likely modify only one small le. This is a big
bene t of the new approa h.
Abhiram Ranade, 2013. Do not distribute 410
Another important bene t arises when we onsider adding new fun tionality to the pro-
gram. Suppose we want to implement layouts of exponential expressions. As you will see,
we an do this without tou hing any of our old les (ex ept the main program le, if we wish
to use exponential expressions, of ourse). The key bene t of this strategy is: we an be sure
that when we add exponential expressions, there isnt even a remote han e of damaging the
old working ode. Programmers (deservedly) tend to be paranoid about their ode, and this
kind of reassuran e is useful. Noti e that if the old ode was written by one programmer, and
the new one by another, then it is very onvenient if one programmer's ode is not tou hed
by another. This way there is larity about who was responsible for what.
24.1.3 Adding exponential expressions
We will add a lass Pow that will represent exponential expressions. This will be a sub lass
of Formula2 sin e it has 2 operands.
lass Pow : publi Formula2{
publi :
Pow(Formula* lhs1, Formula* rhs1){ lhs = lhs1; rhs = rhs1; }
string op(){return "^";}
void draw(float lx, float ly){
lhs->draw( lx, ly);
rhs->draw( lx+lhs->getWidth(),
ly - (lhs->getHeight() - lhs->getDes ent())
- rhs->getDes ent()
);
}
void setSize(){
lhs->setSize(); rhs->setSize();
width = lhs->getWidth() + rhs->getWidth();
height = lhs->getHeight() + rhs->getHeight();
des ent = lhs->getDes ent();
}
};
The basi idea is to layout the exponent above and to the right of the base. The detailed
expressions whi h de ide how to position what are obtained in the manner of Se tion ??,
and are left for you to gure out. Using this lass is simple, to represent X + Y Z we simply
write Sum(new Literal("X"), new Pow(new Literal("Y"), new Literal("Z"))).
The key point to appre iate is that this new ode an be developed independently, in
a new le, without even having the rest of the ode, only the lass header les would be
needed.. If we had used the oding approa h of Se tion 22.1, we would need to have and
modify the old ode.
Abhiram Ranade, 2013. Do not distribute 411
24.2 The simple pp graphi s system
We will dis uss the role played by inheritan e in the design of the simple pp graphi s system.
Although this system is quite small by standards of real graphi s systems, we will not dis uss
the entire system here, but only some relevant portions of it.
Brie y stated, the ore spe i ation of the system is: allow the user to reate and ma-
nipulate graphi al obje ts on the s reen. This statement is very vague, of ourse. What
does it mean to manipulate obje ts? As you know, in simple pp, manipulate simply means
move, rotate, s ale. There are also other questions: what kind of primitives is the user to be
given? Will the user need to spe ify how ea h obje t appears in ea h frame (like the pi ture
frames in a movie) or will the user only state the in remental hanges, e.g. move obje t
x, whi h means the other obje ts remain un hanged? As you know, we have opted for the
latter. And then of ourse there is the question of what kinds of obje ts we an have. As you
know, simple pp supports the following kinds of graphi al obje ts: ir les, lines, re tangles,
polygons, turtles and text.
So in the rest of this se tion, we onsider the problem of reating and manipulating the
obje ts given above, in the manner des ribed above. We will not dis uss issues su h as the
pens asso iated with ea h obje t, or graphi al input, as in the getCli k ommand.
Clearly, su h a system must have the following apabilities:
1. It must be able to keep tra k of the obje ts reated by the user so far.
2. It should be able to display the obje ts on the s reen.
3. It should be able to manipulate the obje ts as requested, e.g. move an obje t.
Let us take item 2 rst. simple pp is built on top of the X Windows system, whi h provides
fun tions that an draw lines, ar s, polygons, ir les ( lled and non- lled) on the s reen, at
the required pla e. So we all these fun tions. Item 3 is also relatively easy. With ea h
obje t we asso iated some on guration data, whi h says how large it is to be drawn, in
what orientation, and where. Note that this data is distin t from the shape data. Item 1
is also not diÆ ult in prin iple: we merely keep a list or a set of some kind in whi h we
pla e ea h obje t. To omplete this very high level des ription we need to answer one more
question: when should the obje ts be displayed? The simplest answer to this is: whenever
the user hanges the state of any obje t, lear the entire display and display all obje ts again.
Inheritan e is useful for fa ilitating many of the a tions des ribed here.
It should be lear that we have the ategory of all graphi al obje ts, and then sub ate-
gories orresponding to di erent types of obje ts, e.g. ir les. So learly, these orrespond to
sub lasses of the lass representing the ategory ALL of all obje ts. Our ategories indeed
form a heirar hy, and so do the asso iated lasses, as shown in Figure 24.1. The lass asso i-
ated with the ategory of all obje ts is alled Sprite, in honour of the S rat h programming
environment (s rat h.mit.edu), where the name is used for a similar on ept.
The heirar hy fa ilitates storing of information as follows. In the Sprite lass we keep
all attributes that are ommon to all graphi s obje ts. At rst glan e, you might think
that pre ious little might be ommon to all the very di erent looking obje ts: ir les, lines,
polygons and so on. But as mentioned earlier, when a graphi s obje t is to be displayed on
the s reen, it will have a position, orientation, s ale in addition to its shape. It will also have
Abhiram Ranade, 2013. Do not distribute 412
ALL (Sprite)

Circle Line Polygon Text

Rectangle Turtle

Figure 24.1: Heirar hy of graphi s obje t ategories

attributes su h as olour. All obje ts will have these attributes. So these attributes be ome
data members in the Sprite lass.
The lasses Cir le, Line, Polygon et . will ontain the shape related attributes (in
addition to all the attributes inherited from Sprite). For example, Cir le ontains a data
member alled radius whi h holds the radius of the ir le being drawn. The Polygon lass
ontains an array whi h holds the oordinates of the verti es of the polygon. As dis ussed
earlier these oordinates are given in a spe ially reated oordinate frame; while drawing
they will be drawn relative to the position of the polygon (as re orded in the Sprite part
of its obje t). Figure 24.2 shows possible ways ontents of the Cir le and Sprite lasses.
The a tual implementations di erent, and you an see them in the ode supplied.
In addition, we must also onsider fun tion members. Suppose we wish to move an
obje t. This requires two a tions: (a) re ording that the obje t has indeed been moved, and
updating its position a ordingly, (b) redrawing the obje t on the s reen. Clearly, a tion
(a) an be performed independent of the shape of the obje t, whereas (b) requires the shape
information. Thus in our implementation, a tion (b) is implemented by a paint method in
ea h shape lass. The move member fun tion is de ned in the Sprite lass. It performs
a tion (a) using the attributes available in the Sprite lass. It then signals that all obje ts
need to be redrawn.
The redrawing works as follows. Essentially simple pp maintains a ve tor that holds
pointers to all obje ts a tive at the urrent instant. Suppose the ve tor is named A tiveSprites,
then its de laration would be
ve tor<Sprite*> A tiveSprites;
Be ause the elements of A tiveSprites have type Sprite*, they an hold pointers to any
graphi al obje t. When the obje ts are to be drawn, we simply iterate over the queue and
exe ute the paint method of the obje t.
for(int i=0; i < A tiveSprites.size(); i++){
A tiveSprites[i℄->paint();
}
The paint method is virtual, and so the paint method in the lass of the obje t is used.
This is similar to the way we used a ve tor of Verb* to store regular and irregular obje ts
and invoked the past tense virtual fun tion on them in Se tion 23.4.
In summary, inheritan e gives us three main bene ts. It is easy to organize our data
strorage manner: the Sprite lass stores the on guration related data and the other lasses
Abhiram Ranade, 2013. Do not distribute 413

lass Sprite{
prote ted:
double x,y; // position on the anvas
double orientation; // angle in radians made with the x axis
double s ale; // s aling fa tor
Color fill_ olor; // Color is a data type in the X windows Xlib pa kage.
bool fill; // whether to fill or not
...
publi :
Sprite();
Sprite(double x, double y);
...
void forward(double dist);
...
virtual void paint()=0;
...
}

lass Cir le : publi Sprite{


private:
double radius;
publi :
Cir le();
Cir le(double x, double y, double radius=10);
void init(double x, double y, double radius=10);
virtual void paint()
};

Figure 24.2: Possible de nitions of Sprite and Cir le


Abhiram Ranade, 2013. Do not distribute 414
store the shape related data. Also be ause of polymorphism and virtual fun tions, we an
store pointers to di erent types of graphi al obje ts (but only subtypes of Sprite) in a single
ve tor, and iterate over the ve tor. Finally, we an add new shapes easily: we simply de ne
a new shape lass whi h is a sub lass of Sprite, without having to modify any existing ode.
We have somewhat simpli ed the des ription of simple pp graphi s in order to explain
the use of inheritan e. The a tual system is more sophisti ated. We see an example of this
sophisti ation next.

24.3 Composite graphi s obje ts


We dis uss how you an de ne a lass whose instan es are omposite, i.e. a single instan e
an ontain several simple obje ts. On e built, you an use the lass in your program to
reate instan es. In de ning a omposite obje t you need inheritan e as we will see.
Suppose you want to draw many ars on the s reen. It would be ni e if you ould
design a lass Car whi h you ould then instantiate to make many ars. A ar is a omplex
obje t: it annot be drawn ni ely using just a single polygon, or a single ir le. It will
require several simple obje ts that simple pp provides. These simple obje ts will have to
be grouped together, and often be manipulated together, e.g. if we want the ar to move, we
really mean to move all its onstituent parts. The lass Composite whi h we dis uss next,
will allow you to group together obje ts. We an then de ne a Car lass by inheriting from
the Composite lass.
Our Composite lass primarily serves as a " ontainer" to hold other graphi s obje ts. It
has a frame of referen e, relative to whi h the ontained obje ts are spe i ed. The Composite
lass has been de ned as a sub lass of the Sprite lass. Thus it inherits member fun tions
su h as move, forward, rotate from the Sprite lass. The Composite lass is designed so
that the member fun tions will ause the ontained obje ts to respond appropriately, i.e.
when you move a Composite, everything inside gets moved. However, you an override
these methods if you wish. For example, suppose your omposite obje t onsists of the
body of a ar and its wheels. When you all forward on this, by default everything will
go forward. You might want the wheels to rotate in addition to moving forward. This an
be a omplished by overridding. You an also additionally de ne your own new member
fun tions whi h do new things. For example, the ar might have a light on the top and there
ould be a member fun tion whi h auses the light to hange olour from white to yellow
(suggesting it is swit hed on). This ould be done using a new member fun tion.
Using the Composite lass is fairly easy. There are only three important ideas to be
understood: the notion of ownership, and the Composite lass onstru tor.
24.3.1 Ownership
A detail we have hidden from you so far is: every graphi s obje t has an \owner". When we
say that obje t X owns obje t Y, we merely mean that obje t Y is spe i ed relative to the
oordinate frame of obje t X. For the obje ts you have been reating so far, the owner was
the anvas: the obje ts were drawn in the oordinate frame of the anvas. When an obje t
is reated as a part of a omposite obje t, it must be drawn relative to the frame of the
Abhiram Ranade, 2013. Do not distribute 415
omposite obje t, and hen e must be owned by the omposite obje t. Thus an important
step in de ning a omposite obje t is to de lare it to be the owner of the ontained obje ts.
To do this, the onstru tor of every graphi al obje t is provided with an optional argu-
ment named owner. This argument takes value NULL by default whi h simple pp interprets
to mean the anvas. Thus so far we did not tell you about this argument, and you didnt not
spe ify the value, and hen e simple pp made the anvas the owner of all the obje ts you
reated. If you want to indi ate a di erent owner, you instead pass a pointer to that owner.
Sin e we reate ontained obje ts in the body of the omposite, we must pass a pointer to
the omposite obje t itself. As you know, inside the de nition of an obje t, the keyword
this denotes a pointer to the obje t. So the extra argument must have this as its value.

24.3.2 The Composite lass onstru tor


The Composite lass onstru tor has the following signature.
Composite(double x, double y, Composite* owner=NULL)

Here the last argument owner gives the owner of the omposite obje t being de ned, and
x,y give the oordinates of the omposite obje t in the frame of its owner. As mentioned
earlier, if you do not spe ify this argument, it is taken as NULL, indi ating that the anvas
is the owner. The owner argument must be spe i ed if this omposite obje t is itself a part
of another omposite obje t. This kind of ontainment is allowed and we will see an example
shortly.
24.3.3 A Car lass
We now onstru t a Car lass. Our ar will onsist of a polygonal body, and two wheels.
We will give the wheels some personality by adding in spokes. So we will model a ar as
a omposite obje t, onsisting of the body and the wheels. But note that a wheel itself
ontains a ir le representing the rim, and lines representing the spokes. So the wheel will
itself have to be represented as a omposite obje t. Note that we allow one omposite obje t
(e.g. a ar) to ontain other ordinary obje ts (e.g. body) or other omposite obje ts (e.g.
wheels).
We begin by de ning a lass for wheels.
lass Wheel : publi Composite{
Cir le *rim;
Line *spoke[10℄;
publi :
Wheel(double x, double y, Composite* owner=NULL) : Composite(x,y,owner) {
rim = new Cir le(0,0,50,this);
for(int i=0; i<10; i++){
spoke[i℄ = new Line(0, 0, 50* os(i*PI/5), 50*sin(i*PI/5), this);
}
}
};
Abhiram Ranade, 2013. Do not distribute 416
There are two private data members. The member rim whi h is de ned as a pointer to the
Cir le obje t whi h represents the rim of the wheel. Likewise spoke is an array of pointers
to ea h spoke of the wheel. The obje ts themselves are reated in the onstru tor. This is a
very ommon idiom for de ning omposite graphi s obje ts.
The onstru tor ustomarily takes as argument a pointer to the owner of the omposite
obje t itself, and the position of the omposite obje t in the frame of the owner. It is
ustomary to assign a default value NULL for the owner parameter, as dis ussed earlier. The
initialization list Composite(x,y,owner) merely forwards these arguments so that the ore
omposite obje t is reated at the required oordinate and gets the spe i ed owner. Inside
the onstru tor, we reate the sub-obje ts. So we reate the ir le representing the rim, and
as you an see we have given it an extra argument this, so that the Wheel obje t be omes
the owner of the rim. Likewise we reate lines at di erent in linations to represent the
spokes, and even here the extra argument this auses the lines to be owned by the Wheel
obje t.
The Car lass an be put together by using Wheel instan es as parts.
lass Car : publi Composite{
Polygon* body;
Wheel* w1;
Wheel* w2;
publi :
Car(double x, double y, Color , Composite* owner=NULL)
: Composite(x,y,owner){
double bodyV[9℄[2℄={{-150,0}, {-150,-100}, {-100,-100}, {-75,-200},
{50,-200}, {100,-100}, {150,-100}, {150,0}, {-150,0}};
body = new Polygon(0,0, bodyV, 9, this);
body->setColor( );
body->setFill();
w1 = new Wheel(-90,0,this);
w2 = new Wheel(90,0,this);
}
void forward(double dx, bool repaintP=true){
Composite::forward(dx,false); // super lass forward fun tion
w1->rotate(dx/50,false); // angle = dx/radius
w2->rotate(dx/50,false);
if(repaintP) repaint();
}
};
As will be seen, the private members are the pointers to the body and the two wheels. In
the onstru tor, the body is reated as a polygon. We have provided a parameter in the
onstru tor whi h an be used to give a olour to the body. Finally, the wheels are reated.
For all 3 parts, the last argument is set to this, be ause of whi h the parts be ome owned
by the Car obje t, as we want them to be.
The de nition also shows the forward fun tion being overridden. As dis ussed, we want
the ar to move forward, whi h is a omplished by alling the forward fun tion of the super-
Abhiram Ranade, 2013. Do not distribute 417
lass. But we also want the wheels to turn; this is a omplished by rotating them. Clearly,
if the ar moves forward by an amount dx, then the wheels must rotate by dx/r radians,
where r is the radius of the wheels. But why does the rotate fun tion alled with an extra
argument false? And why is the fun tion repaint alled? We explain these next.
24.3.4 Frames
Another detail of simple pp graphi s whi h we have withheld from you is that all the
on guration hange ommands, i.e. forward, move, rotate and so on have an additional
argument repaintP whi h takes the default value true. If repaintP is true, then the anvas
is repainted as dis ussed in Se tion 24.2 after every on guration hange. If repaintP is
false, then the repainting is not done, only the on guration hange is re orded.
This feature is useful espe ially when invoking a on guration hange ommand on sub-
obje ts omprising a omposite obje t. We do not want repainting to happen after a move of
ea h subobje t. It is ineÆ ient and also auses visually annoying. Rather we want repainting
to happen on e, after the on guration hange is re orded for all subobje ts. This is what
the ode above a omplishes: no repainting happens after the Composite::forward as well
as the two w...->rotate operations. Repainting is done only at the end unless it is disabled
by the aller to Car::forward.
24.3.5 Main program
Finally, here is a main program that might use the above de nitions.
int main(){
initCanvas("Car",0,0,800,800);

Car (300,300,COLOR("blue"));
Car d(300,600,COLOR("red"));
d.s ale(0.5);
getCli k();

for(int i=0; i<100; i++){


.forward(3.0,false);
d.forward(1.5,false);
repaint();
}
getCli k();
}
The main program reates two ars, one blue and another red. The red ar is then s aled
to half its size. This auses all the omponents of the ar to shrink { this is handled
automati ally by the ode in the Composite lass.
Finally, we move the ars forward. When you exe ute this, the ar wheels should appear
to roll on the ground. Further, the wheels of the smaller ar should appear to have twi e as
many rotations per unit time be ause the smaller wheel has half the radius but is travelling
the same distan e as the larger wheel.
Abhiram Ranade, 2013. Do not distribute 418
Exer ises
1. To the program of Se tion 24.1 add the apability of drawing summation formulae, i.e.
formulae B X
C
A

where A; B; C an themselves be formulae.


2. De ne a omposite obje t to model a fa e. De ne methods for showing emotions, e.g.
smiling. Use your imagination.
3. An attra tive idea in the S rat h programming system is of ostumes for sprites. A
ostume is merely a des ription of how a sprite an appear. For example, a bird sprite
might have two ostumes: one in whi h the wings are together, and another in whi h
the wings are spread out. By alternating between the two ostumes as the bird moves,
you an reate the e e t of the bird ying. Design this sprite.
4. Do you think it will be possible to design a lass CostumedObje t whi h an make it
easier to de ne multiple ostumes? If so do it.
5. You are to write a program using whi h non-programmers an write simple animations.
The input to the program ould be something like the following sequen e of ommands.
Cir le 100 200 5
Re tangle 200 300 40 50
Cir le 100 200 15
Move 0 50 50
Left 1 30
Move 2 70 -70
Wait 0.5
...

In this, the rst 3 lines de ned 3 obje ts. As you might guess, the numbers following
the shape names are the arguments for the orresponding onstru tors. For the rest
of the sequen e, the onstru ted obje ts respe tively get numbered 0, 1, 2 (or till as
many obje ts as we have de ned). In the rest of the ommand sequen e, a graphi al
obje t will be referred to by its number. Thus the ommand Move 0 50 50 auses
obje t 0 (the rst ir le) to be displa ed by 50, 50 along x and y dire tions. Likewise
Left 1 30 auses the re tangle to be rotated left by 30 degrees. You may also de ne
ommands to wait for spe i ed amount of time.
Write the program. Note that Sprite obje ts annot be stored in a ve tor. However,
you an reate the Sprite on the heap and store a pointer to it in a ve tor.
Chapter 25

Dis rete event simulation

We have already dis ussed the general notion of simulation: given the urrent state and laws
of evolution of a system, predi t the state of the system at some later date. In Chapter 17, we
onsidered the simulation of heavenly bodies, as might be required in astronomy. However,
simulation is very useful also for more mundane, down to earth systems. A very ommon
use of simulation is to understand whether a fa ility su h as a restaurant or a train station
or airport has enough resour es su h as tables or platforms or runways to satisfa torily serve
the ustomers or travellers that might arrive into it.
As a on rete example, suppose we want to de ide how many dining tables we should put
in a restaurant. If we put too few tables, we will not be able to a ommodate all ustomers
who might want to eat in our restaurant. On the other hand, ea h table we put in has a ost.
So we might want to determine, for ea h T where T is the number of tables we put, what our
revenue is likely to be. Knowing the revenue and the ost of putting up tables, we should be
able to hoose the right value of T . To do this analysis, we of ourse need to know something
about how many ustomers want to eat in our restaurant, and when. This an be predi ted
only statisti ally. We will assume that we are given p, the probability that a ustomer arrives
in any given minute of the \busy period" for restaurants, say 7 pm to 10 pm. Ideally, we
should onsider not single ustomers but a party onsisting of several ustomers, and the
possibility that a ustomer party might need more than one table. However, for simpli ity
we will assume that ustomers arrive individually and are seated individually at separate
tables. On arrival, a ustomer o upies the table for some time during whi h he eats, and
then leaves. Suppose that we are also given a fun tion e(t), that gives the probability that
a ustomer eats for t minutes. For simpli ity, suppose that the revenue is proportional to
the total number of ustomers. Can we determine the total revenue for an arbitrary value
of T , the number of tables we have? Note that an arriving ustomer will leave if all tables
are o upied.
Problems su h as this one an sometimes be solved analyti ally, i.e. we an write the
expe ted revenue as a reasonably simple, easily evaluatable fun tion of the di erent param-
eters. But this is often not possible if the probability model is omplex. For example, in the
above des ription, we implied that the eating time probability distribution e(t) is a fun tion
only of t. But if there are many people in the restaurant, the servi e might will be slower
and ea h ustomer will o upy the table for longer periods. Thus perhaps the distribution
should be a fun tion of the number of ustomers present as well. In this ase, it will be

419
Abhiram Ranade, 2013. Do not distribute 420
mu h more diÆ ult to write down an analyti al solution. In su h ases, a ommon strategy
is simulate the system. By this we mean the following. We pi k random numbers from
appropriate distributions to de ide when ustomers arrive, how long they wait. Using this
information we ompute how many tables are o upied at ea h instant, whi h ustomers
need to be turned away be ause the restaurant is full and so on.
In this hapter we will see how to perform this simulation. This simulation has a very
di erent hara ter from the osmologi al simulation of Chapter 17. We will see that it is
an example of a Dis rete Event Simulation, whi h we onsider at length in Se tion 25.1.
We will develop some ma hinery to perform dis rete event simulations using whi h we will
perform the restaurant simulation. We will also onsider a variation, whi h we will all the
o ee shop simulation. The last topi in this hapter is the shortest path problem for graphs.
We an get a fast algorithm for this abstra t problem by viewing it as a simulation of a
ertain natural system. In Chapter 26 we develop a simulation of an airport, whi h uses the
ma hinery we develop in this hapter.

25.1 Dis rete event simulation overview


In a osmologi al system ea h star attra ts, and thereby a e ts, every other star at every
time instant. In ontrast, in many other real life systems the entities intera t with ea h
other relatively infrequently. For example, in a restaurant, a ustomer has intera tions
su h as getting a table, ordering food, being served, paying the bill and leaving. These
intera tions are typi ally separated by long periods during whi h the ustomer is typi ally
neither disturbed, nor demands any attention. Thus it is ustomary to all this latter kind
of system a dis rete time system, whereas the former kind is alled a ontinuous time system.
25.1.1 Dis rete time systems
In general, a dis rete time system onsists of a ertain number of entities whi h might have
states that an hange over time. In addition there is a list of enabled/impending events,
i.e. events that are known will o ur, ea h at some spe i ed time in the future. When an
event a tually o urs, it may ause (a) the state of some of the entities to hange, and (b)
more events to be reated. The new state depends upon the event that happened as well
as the old state. Likewise the new events that are reated also depend upon the event that
happened and the old state, i.e. the state of the entities just before the event happened. It
is to be further noted that the state of a dis rete system an hange or new events reated
only during the o urren e of some event.
Many real life systems an be onsidered to be dis rete time systems. For example,
onsider our restaurant system as des ribed earlier. We have a very simple model in whi h
ustomers approa h and they are seated if there is a table available, and then leave after a
ertain randomly hosen time duration. If there is no table available, then we may onsider
that they do not even enter the restaurant. In this ase it is natural to think of the tables
in the restaurant as the entities, and these an either be in the o upied or not o upied
states. We may onsider two kinds of events: ustomer approa h, and ustomer Exit. Here
is what happens during the o urren e of these events:
Abhiram Ranade, 2013. Do not distribute 421
S : State of the entities in the system. Initialized to the state at the urrent time.
L : List of events. Initialized to ontain the events that are known will happen after the
urrent time.
1. Let e be the event with the smallest time of o urren e.
2. Remove e from L.
3. Pro ess e. This will ause hange to S . New events may also be added to L.
4. Repeat from step 1 if L is not empty.
Figure 25.1: Dis rete Event Simulation Algorithm
Approa h: If all tables are o upied, then nothing happens. If there is an uno upied
table, then the number of o upied table in reases by one, and an Exit event is reated
for o urren e at the urrent time + E , where E denotes the duration for whi h the
ustomer eats.
Exit: The number of o upied tables redu es by one. No event is reated for any future
time.
As you an see what happens during the o urren e of the events does depend upon the
state of the world at the time of the o urren e. But this is what we stated in the de nition
above of dis rete time systems.
We will further note that it is ustomary to onsider the o urren e of an event in dis rete
time systems to be instantaneous. This is not to say that a tions su h as eating are meant
to be instantaneous. Indeed, as you saw above, eating starts with the approa h event and
nishes in the exit event.
We will see other examples shortly.
25.1.2 Evolution of a dis rete time system
A key point to note is that if we know the state of a dis rete time system at a given time and
all the impending events, i.e. events that were reated earlier but whi h havent yet o urred,
we an pre isely determine how the system evolves.
To see this, note that the urrent state of the system must persist until some event o urs.
Thus in parti ular, the urrent state must remain un hanged till the earliest of the impending
events o urs. But we know the state at the time of this earliest event { it is simply the
urrent state { and so we an pre isely determine the e e t of the earliest impending event.
In other words, we will know how it will hange the state and what new events will get
reated. But then we an keep going in the same manner, i.e. onsider the next earliest
event and determine its e e t. The algorithm for this is abstra tly given in Figure 25.1.
Abhiram Ranade, 2013. Do not distribute 422
25.1.3 Implementing a dis rete time system
The important question is how we represent the system state and events on a omputer.
Usually, the state of a system has a natural representation. For example, in our restaurant
problem, we only need a single variable whi h keeps tra k of the number of o upied tables.
How to represent events is more interesting.
When we say an event o urs, we typi ally have in mind a ertain set of a tions that takes
pla e. Thus, it is natural to asso iate an event with a fun tion whi h performs the required
a tions. The fun tion must have a ess to the state of the system, and must be alled
only when the asso iated event be omes the earliest pending event, i.e. after earlier events
have been pro essed. Thus it turns out to be natural to represent ea h event by a lambda
expression (Appendix H), in parti ular a fun tion that takes no arguments and returns no
results. When it is time for the event to o ur, we simply all the lambda expression! The
following dis ussion will make heavy use of lambda expressions, and hen e it is re ommended
that the reader be ome familiar with Appendix H.
As dis ussed in Appendix H, the type of a lambda expression denoting a fun tion that
takes no arguments and returns no value is std::fun tion<void()>. It will be onvenient
to assign a name to this type.
typedef std::fun tion<void()> Event;
The me hanism of variable apture in lambda expressions will enable the fun tion to get
a ess to the system state, as we will see.
Se ond, for onvenien e we will make the event list L of Figure 25.1 hold pairs of the form
(e; t) where e is the event and t the time at whi h it is to happen. The (e; t) pairs that we
need will be represented using the pair lass in STL (found in the header le <util>). We
use the type double to represent time, so we need a pair of Event and double. To simplify
the subsequent dis ussion it is onvenient to de ne:
typedef pair<Event,double> ETpair;
Remember that the event list, onsisting of pairs (e; t), is a essed in a very spe ial manner.
As seen in Figure 25.1, we do not remove arbitrary pairs from the list but only those with
smallest t, though we may insert pairs in any order.
The priority queue template lass in STL (found in header le <queue>) supports
nearly this mode of operation. It has operations return the \largest" element in the queue,
where we an de ne what is largest. Here is the prototype for priority queue.
template< lass T, // argument 1
lass C = ve tor<T>, // argument 2
lass mp = less<typename C::value_type> // argument 3
> priority_queue;
A prototype of a template is similar to a fun tion prototype: both give the arguments and
their types, and possible default values. In this ase, the priority queue template takes 3
arguments. The se ond argument C spe i es the ontainer lass using whi h the elements
in a priority queue will be stored. The default option is to use a ve tor, whi h we do not
wish to hange. The third argument mp is used to de ide what to return. It defaults to
Abhiram Ranade, 2013. Do not distribute 423
less, whi h is simply the operator <. Thus of all the elements stored in it a priority queue
returns that element x su h that there is no y su h that x < y. Thus a largest element is
returned. To get a smallest instead, we must make the third argument be the equivalent of
the > operator. This is done using the lass ompareETpair, shown in Figure 25.2.
The lass sim shown in Figure 25.2 is the main simulation lass. The member pq in it
holds the event list. In addition to the event list, the lass also has a member time whi h is
meant to hold the time till whi h the system has been simulated. We start o by initializing
time to 0.
This lass sim is a little unusual. It is not meant to be instantiated! The members time
and pq are de ned as stati elements. Thus there will be only one opy of pq and time,
but this is exa tly what we want. The fun tionality is provided through four stati member
fun tions. Note that stati member fun tions an be a essed outside the lass de nition as
lass-name::fun tion-name.
The member fun tion post allows an event to be posted, i.e. reated and inserted into
the priority queue. The rst argument laten y is the time duration after whi h the event is
to happen, from the urrent time of the system. The se ond argument e is the event itself.
The fun tion thus inserts the pair (e, time + laten y) into the priority queue.
The member fun tion getTime merely returns the urrent time, i.e. the time till whi h
the system has been simulated.
The member fun tion pro essAll pro esses posted events till nothing is left to pro ess.
For this, it repeatedly pi ks the pair (e; t) in the priority queue with the smallest time t and
alls the event e. Note that when we pi k the element with the smallest time t, we know
that the system time an be advan ed to t. Thus the member time is updated to t. Note
that the smallest element in the queue an be removed by using the pop method, or we an
just examine it using the top method.
The last method, log, is for reporting onvenien e. It is used to print messages to the
s reen, but ea h message is prefa ed by the urrent time. Note that a referen e to the
onsole output, out is returned, so that the rest of the message an be appended using the
<< operator.

25.1.4 Simple examples of use


In general to use any lass su h as sim, you must ompile it along with your program, or
in lude a suitable header le et . However, to simplify matters for you, we have in luded
sim in simple pp itself. Thus you dont need to do anything other than in lude simple pp.
We begin with some simple simulation examples. Given below is a program that just
reates 2 events, say A,B and then asks the simulator to pro ess them.
int main(){
sim::post(15, [℄(){sim::log() << "Event A.\n";}); // event A
sim::post(5, [℄(){sim::log() << "Event B.\n";}); // event B

sim::pro essAll(); // pro ess all events.


}
The a tion asso iated with ea h event is simple: a message is printed, with the urrent
simulation time.
Abhiram Ranade, 2013. Do not distribute 424

lass sim{
typedef std::fun tion<void()> Event;
typedef pair<Event,double> ETpair;
stru t ompareETpair{
bool operator()(ETpair p, ETpair q){return p.se ond > q.se ond;}
};
stati double time; // time to whi h the system has been simulated
stati priority_queue< ETpair, ve tor<ETpair>, ompareETpair> pq;

publi :
stati void post(double laten y, Event e){
pq.push(make_pair(e, time + laten y));
}

stati double getTime(){return time;}

stati void pro essAll(double tmax=1000){


while(!pq.empty() && time < tmax){
ETpair ETp = pq.top();
time = ETp.se ond;
pq.pop();
ETp.first();
}
}

stati ostream & log(){


out << time << ") ";
return out;
}
};

// Initialization of the stati elements.

double sim::time = 0;
priority_queue< sim::ETpair, ve tor<sim::ETpair>, sim:: ompareETpair> sim::pq;

Figure 25.2: The main simulation lass


Abhiram Ranade, 2013. Do not distribute 425
When you exe ute, the rst two statements will ause events A, B to be posted to o ur
15 and 5 time units respe tively from the urrent time. The simulation starts with time 0,
so these events will o ur at time 15 and 5 respe tively. The third statement in the program
will ause the system to be evolved, i.e. all the events in the queue will be pro essed, in the
order of the time at whi h they are meant to o ur. Thus event B, s heduled at time 5, will
get pro essed, rst, i.e. its lambda expression will be alled. This will ause the message
\Event B." to be printed, pre xed by the simulation time, be ause of the all to sim::log.
After that event A will be pro essed. Thus you would get the following output.
5) Event B.
15) Event A.

The point to be noted is that in the program the reation of event A happens before the
reation of event B. However, the time of A, 15, is larger than the time of B, 5. Hen e B
happens before A during the exe ution.
As we dis ussed in Se tion 25.1.1, events in a dis rete time system will in general ause
the state of some of the entities to hange, and also ause the reation (posting) of new
events. We will now onsider an example in whi h events do both of these. This example
will be ontain the ore idiom used in all future simulations.
In the program below, we have 4 events, A, B, C, D. We also have a variable ount. We
will see that the events will a ess this variable (\simulation state"), and in fa t event D will
be posted during the o urren e of event C.
int main(){
int ount=0;
sim::post(15, [&℄(){sim::log() << "A. ount: "<< ount++ <<endl;}); //A
sim::post(5, [&℄(){sim::log() << "B. ount: "<< ount++ <<endl;}); //B
sim::post(10, [&℄(){ //C
sim::log() << "C. ount "<< ount++ <<endl;
sim::post(100, [&℄(){sim::log() << "D. ount: " << //D
ount++ << endl;});
});
sim::pro essAll();
}

The program begins by setting ount to 0, and then posting the events A, B, C for time 15,
5, 10 respe tively. Then sim::pro essAll auses the posted events to be pro essed.
The event posted for the earliest time is event B, and hen e that gets pro essed rst.
This will ause the time of o urren e of B to be printed and also the value of ount. Note
that ount has been aptured into the event by referen e, and hen e the value at the time
of o urren e of the event will be printed. Thus we will see the following output.
5) B. ount: 0
Note that while printing, ount is also in remented. Sin e ount was aptured by referen e,
the in rement will a e t the variable ount as de ned in the rst line of the program. Thus
this will be ome 1.
Abhiram Ranade, 2013. Do not distribute 426
The event posted for the next earliest time, 10, is event C, whi h is then pro essed. The
pro essing starts o by printing the message and the value of ount. Noti e that even in
event C the variable ount has been aptured by referen e. Thus the following message will
be printed
10) C. ount: 1
and ount will be in remented. But the pro essing of event C does not stop after printing
the message. After printing, the all sim::post is exe uted, whi h auses event D to be
reated, as a part of the o urren e of the event C. Event D is to o ur at 100 steps after
the urrent time, i.e. 10. Thus event D gets posted for time 110. Thus when the pro essing
for C nishes, there are two events, A, D in the queue, and the value of ount is 2.
Again, the earliest of the events is pro essed, i.e. event A. This will print a message:
15) A. ount: 2
and will in rement ount to 3.
After that event D will be pro essed. This will print a message:
110) D. ount: 3

and ause ount to in rement to 4. Note the time in the message { sim::log will indeed
print 110, the time at whi h we expe t the event to o ur.

25.2 The restaurant simulation


We now show how to program the restaurant simulation. It is hara terized by a number of
parameters, the restaurant apa ity (i.e. the number of tables), the time duration in minutes
for whi h the restaurant remains open, the probability that a ustomer arrives in the next
minute, and the minimum and maximum eating time for the ustomers. The restaurant
state onsists of the number of tables that are o upied.
At ea h minute that the restaurant is open, a ustomer an arrive with the spe i ed
probability. We model ea h arrival as an event. On arrival, the ustomer he ks if there are
uno upied tables, if not the ustomer leaves and we should print a message to that e e t.
If however there are uno upied tables, then the ustomer o upies one and sits down to eat.
Then an eating duration is randomly hosen, and the ustomer must exit the restaurant after
that duration. We model the exit also as an event. Thus the arrival event for the ustomer
must perform the above a tions, in luding the reation of the exit events. All this goes into
the lambda expression for the arrival events. On exit, it is only ne essary to de rement the
number of o upied tables. Thus the de rementation ode must be pla ed in the lambda
expression of the exit event.
Thus the ode is as follows.
int main(){
onst int apa ity=5; // number of tables
onst int duration=180; // minutes open
double arrivalP=0.1, eatMin=21, eatMax=40;
Abhiram Ranade, 2013. Do not distribute 427
int nO upied = 0 ; // number of tables o upied
int id = 0;

for(int t=0; t<duration; t++){


if(randuv(0,1) <= arrivalP){ // with probability arrivalP
id++;
sim::post(t, [=,&nO upied℄(){
if(nO upied >= apa ity) // if no table available
sim::log()<< " Customer " << id << " disappointed.\n";
else{ // if a table is available
++nO upied;
int eatTime = randuv(eatMin, eatMax);
sim::log()<<" Customer " << id << " will eat for "<<eatTime<<"\n";
sim::post(eatTime, [=,&nO upied℄(){
sim::log()<< " Customer " << id << " finishes.\n";
--nO upied;
});
}
});
}
}
sim::pro essAll();
}

25.3 Resour es
Many real life systems ontain resour es that are s ar e. For example, the same ma hine
might be needed to pro ess several jobs of whi h it might be apable of pro essing only one
at any instant. In su h ases, the jobs must wait to gain ex lusive a ess to the ma hine.
As an example, onsider a roadside o ee shop manned by a single server. Suppose the
shop serves beverages and food, all of whi h require some e ort and time from the server. If
a ustomer arrives while the server is busy with a previous ustomer, then the new ustomer
must wait. So a line of waiting ustomers might form at popular o ee shops. Given the
probability of ustomer arrival and the probability distribution of the servi e time, an we
predi t how mu h business the shop gets and also how long the line be omes?
We will develop a Resour e lass whi h will make it easy to write su h simulations.
25.3.1 A Resour e lass
So far, we have said that events an be reated and posted to o ur at a ertain time in
the future. We will extend this notion and allow an event to be posted to o ur when a
ertain resour e be omes available. If the resour e is immediately available, then the event
will o ur immediately. Otherwise, it will be put in a queue asso iated with the resour e.
When the resour e be omes available, be ause some other event releases it, the waiting event
will be taken o the queue and posted for immediate exe ution.
Abhiram Ranade, 2013. Do not distribute 428
These ideas are implemented in a Resour e lass.
lass Resour e{
typedef std::fun tion<void()> Event;
queue<Event> q;
bool inUse;
publi :
Resour e(){inUse = false;};
int size(){ return q.size(); }
bool reserve(){
if(inUse) return false;
else{ inUse = true; return true;}
}
void a quire(Event pS){
if (!inUse){
inUse = true;
sim::post(0,pS);
}
else
q.push(pS);
}
void release(){
if(!q.empty()){
Event x = q.front();
q.pop();
sim::post(0,x);
}
else inUse = false;
}
};
We an reate instan es of the Resour e lass to model resour es whi h must be used
ex lusively. The data member inUse in Resour e whi h if true denotes that the resour e
(represented by the instan e) is deemed to be in use, and if false denotes that the resour e
is available. In addition, the resour e lass has a data member q whi h is a queue from the
standard template library. You an add elementes to (the end of) a queue by alling the
member fun tion push, examine the element at the front of a queue by allig the member
fun tion front, and remove the element at the front by alling the member fun tion pop.
The member fun tion a quire an be used to get ex lusive a ess to the resour e. It takes
as argument the event e that needs ex lusive a ess, i.e. the lambda expression whi h will
be exe uted when the resour e be omes available. If the resour e is immediately available,
the event is posted for immediate exe ution by alling sim::post(0,e). That the resour e
has been a quired is represented by setting inUse = true. If the resour e is not available,
then the event is put in the queue asso iated with the resour e.
The member fun tion release an be used to release a resour e and make it available to
other events. If an event e is waiting in the queue (front) of a resour e that is being released,
Abhiram Ranade, 2013. Do not distribute 429
then e is posted for immediate exe ution by alling sim::post(0,e). Note that in this ase
we do not need to hange inUse: it was true before and must remain true be ause we
assigned the resour e to the waiting event. If there was no event waiting in the queue, then
we must set inUse = false, so that a future a quire request an su eed immediately.
Finally, there is a member fun tion reserve whi h marks the resour e as being in use
and returns true if and only if the resour e was not in use earlier. We will see a use of this
in Se tion 26.6.
25.3.2 Simple example
The Resour e lass is also a part of simple pp, and so is immediately available for use.
Here is a simple example.
int main(){
Resour e r;

sim::post(15, [&℄(){
r.a quire([℄(){sim::log() << "Got it! \n";});
});

r.a quire([&℄(){
sim::post(20, [&℄(){
r.release();
});
});
sim::pro essAll();
}
The rst statement posts an event for time 10, in whi h the resour e r is sought to be
a quired. Upon a quisition a message will be printed giving the time at whi h the a quisiton
su eeds. The se ond statement seeks to a quire r immediately (at time 0), and releases it
20 steps after a quisition.
As you an see, the a quisition in the se ond statement will su eed, sin e at time 0 the
resour e is available. Thus the resour e will get released 20 steps afterwards, i.e. at time 20.
Thus the a quisition in the rst statement will su eed at time 20. Thus that is when the
message \Got it!" will be printed. Thus the output of the program will be:
20) Got it!
Note that r needs to be aptured in the se ond statement. Sin e r is shared between the
statements, it is aptured by referen e.
25.3.3 The o ee shop simulation
Using the Resour e lass, the simulation is easily written. The main program for simulating
a 180 minute duration is as follows.
Abhiram Ranade, 2013. Do not distribute 430
int main(){
onst int duration=180; // minutes open
double arrivalP = 0.1;
int id = 0;
Resour e server;

for(int t=0; t<duration; t++){


if(randuv(0,1) <= arrivalP){ // with probability arrivalP
id++;
int servi eT = randuv(3,9);
sim::post(t, [=,&server℄(){
sim::log() <<" "<< id << " arrives, servi e time "<< servi eT <<endl;
server.a quire([=,&server℄(){
sim::log() << " Customer: " << id << " being served.\n";
sim::post(servi eT, [=,&server℄(){
sim::log() << " Customer: " << id << " finishes.\n";
server.release();
});
});
});
}
}
sim::pro essAll();
}
The general outline is similar to the restaurant simulation. We need a Resour e to model
the server, whi h is alled server in the ode. Then for ea h minute we simulate ustomer
arrival, with the arrival probability arrivalP. If a ustomer is deemed to arrive, then we
generate a random servi e time for the ustomer. Then we must perform the following
a tions.
1. Print out a message saying that a ustomer arrives, along with the servi e time.
2. Request ex lusive a ess to the server.
3. On getting ex lusive a ess, we hold the server for the servi e time.
4. After the servi e time elapses, we release the server.
As you an see, the ode above exe utes exa tly these steps. However, the steps appear
nested. This is be ause the ode for an event is required to be pla ed in the argument list
of the pre eding event.
We note some important points about variable apture. First, server is shared a ross
iterations, and hen e must be aptured by referen e. However, we want the value of the
variable id from the time of when the ustomer arrival is posted. Hen e id must be aptured
by value. Finally servi eT is a lo al variable inside the loop, so it must be aptured by
value. Hen e we have asked that all variables be aptured by value ex ept for server whi h
must be aptured by referen e.
Abhiram Ranade, 2013. Do not distribute 431
Nagpur
500
Nashik

200

Mumbai 220
160

Pune
50
450
Satara

300

Kolhapur

Figure 25.3: S hemati Map


25.4 Single sour e shortest path
In this se tion we onsider the single-sour e-shortest-path problem. Suppose we are given
information about whi h ities are dire tly onne ted by road, and the length of all su h
roads. We want to travel from a given origin ity to a destination ity by road, passing
whatever ities along the way, so that the total distan e overed is as small as possible. The
problem is diÆ ult be ause there an be several paths from the origin to the destination,
depending upon whi h ities you hoose to pass through along the way. Of all su h possible
paths, we want the shortest. We will fo us on the problem of nding the the length of the
shortest path, the path themselves an be identi ed with a little additional book-keeping,
whi h is left for the Exer ises. We dis uss a lassi algorithm, attributed to Edsgar Dijkstra.
The algorithm a tually nds the distan e from the origin to all other ities, be ause that is
onvenient.
Dijkstra's algorithm an be viewed as a omputer analogue of the following physi al
experiment you ould undertake to nd the distan es. For the experiment we need many
y lists who an ride at some onstant speed, say 1 km/minute. Spe i ally, we need to have
as many y lists in ea h ity as there are roads leading out of it. If we do have su h y lists,
here is how they ould ooperatively nd the length of the shortest paths.
To start with, all the y lists assemble in their respe tive ities. Ea h y list is assigned
one road leading out of the ity, and the job of the y list will be to travel on just that one
road when asked to. After the y list is agged o somehow, she starts pedalling and rea hes
the ity at the other end of the road. Here she must he k if she is the rst y list to arrive.
Abhiram Ranade, 2013. Do not distribute 432
If she is not the rst, i.e. someone arrived earlier, then she does nothing and stops. If she is
indeed the rst to arrive, then she ags o all the waiting y lists to start pedalling. After
that her job is over.
Here is how the experiment starts o . At time 0, a titious y list arrives into the origin
ity, and ags o the y lists in that ity. They then ag o other y lists as des ribed
above. The experiment ends when all y lists have nished their journey.
As an example, suppose our graph is the map of Figure 25.3, and we want the distan es
from Nashik. So at time 0, a titious y list arrives into Nashik and ags o the y lists
there. So y lists start pedalling from Nashik to respe tively Nagpur, Mumbai and Pune.
The y list from Nashik arrives at time 200 into Mumbai, where we are measuring time in
minutes from the start. She is the rst one to arrive there, so she ags o the 3 Mumbai
y lists who then start travelling towards Kolhapur, Pune, and Nashik respe tively. Of these
3 the y list heading to Pune would rea h 160 minutes later, at time 360. However, when
she rea hes Pune, she would have found that the y list from Nashik has already arrived at
time 220. So the y list arriving from Mumbai into Pune would need to do nothing. In this
manner the pro ess ontinues.
We will show that: (a) the length of the shortest path from the sour e to any ity is
simply the time in minutes when the earliest y list arrives in that ity! (b) we an use
dis rete event simulation to simulate this system.
We explain (a) rst. Let S denote the sour e ity, and C be any ity. Let t be the time
at whi h the rst y list arrives into C . We argue that there must be a path from S to
C of pre isely this length. To see this, onsider the y list that arrives into C . We follow
this y list ba kward in time to the ity from whi h he started. There, he was agged o
by some other y list, whom we follow ba k in time, and so on. Eventually, we must rea h
the ity S , at time 0. In this pro ess, note that we are not only going ba k in time but
also ontinuously travelling ba k, at 1 km/minute. Thus, we must have overed, ba kwards,
exa tly the same distan e as the time taken. Thus we have proved that there exists a path
from S to C of length equal to the time at whi h the rst y list arrives in C . We now prove
that it is the shortest.
Consider a shortest path P from S to C , the ities on it being ; ; : : : ; k in order, with
0 1
= S , and k = C . Let di be the distan e from to i along the path. We will prove that
0 0
the rst y list ( titious or real) to arrive at i does so no later than di, for all i. Clearly,
this is true for i = 0: indeed a y list arrives at at 0 = d . So assume by indu tion that a
0 0
y list arrives at i at time di or before. Thus a y list must have left i at time di or before
for ity i . But this y list travels at 1 km/minute, and hen e overs the distan e di di
+1 +1
also in time di di. Hen e he will arrive at i at time at most di + di di = di . Thus
+1 +1 +1 +1
the indu tion is omplete. Thus we know that some y list must arrive at k = C at time at
most the length of the shortest path P . But we proved earlier that the time of arrival must
equal the length of some path. Hen e it follows that the rst y list arrives at time exa tly
equal to the length of the shortest path.
We next show that our algorithm an be programmed as a dis rete event simulation.
Abhiram Ranade, 2013. Do not distribute 433
25.4.1 Dijkstra's algorithm as a simulation
The rst question, of ourse, is how to represent our network of roads. The network is a graph,
in whi h the ities are the verti es and the roads the edges. So we use the representation as
given in Se tion 21.1.4. This is shown in Figure 25.4.
The entire road network is held inside the lass RoadNetwork. It ontains a ve tor,
ities, the ith element of whi h is an obje t of lass City ontaining information about the
ith ity. Thus we must assign a number to ea h ity in our map. For our map of Figure 25.3,
we assign the numbers 0 to 5 to the ities Kolhapur, Mumbai, Pune, Nashik, Nagpur, Satara
respe tively. The member arrivalT in ea h City obje t is meant for storing the time at
whi h the rst y list arrives into that ity. Ea h City obje t also ontains a ve tor roads
whi h stores information about the roads leaving that ity. Suppose G is a RoadNetwork.
Then G. ities[i℄.roads[j℄ is an obje t of type Road whi h stores information about the
jth road leaving ity i. Spe i ally the obje t stores the following: (a) a pointer toPtr to
the ity that this road leads to, (b) a double length giving the length of this road.
The onstru tor for the lass RoadNetwork reads in the road network from the le whose
name is given as an argument. Figure 25.5 shows a sample input le. This le represents
the road network of Figure 25.3. The rst number in the le gives the number of ities.
On reading this the onstru tor resizes the ve tor ities to this number. This will ause
elements of the ve tor ities to be reated. Thus a City obje t is reated for ea h ity in
the network. Note the onstru tor for City: it sets arrivalT to HUGE VAL, whi h represents
1. We use this to denote that as of now, no y list has arrived into the ity. Next, the
onstru tor of RoadNetwork reads information about the roads in the graph. This onsists
of triples 1, 2, dist, where 1, 2 give the ities at the two ends of a road, and dist
gives the length of the road. We must store the information about this road in the stru ture
ities[ 1℄ whi h stores information related to ity 1, as well as in ities[ 2℄ whi h
stores information related to ity 2. That is done in the two statements in the loop. When
the loop nishes, the road network will have been onstru ted.
The lass RoadNetwork also ontains the arrive member fun tion, whi h we will dis uss
later.
The main program reates the graph, and starts o the simulation of the movement of
the y lists, as shown below.
int main(int arg , har** argv){
RoadNetwork G(argv[1℄); // reate road network from file
int origin; // ity from whi h distan es are needed
stringstream(argv[2℄) >> origin;

// ause the fi titious y list to arrive.


sim::POST(0, [&G,origin℄(){G. ities[origin℄.arrive();});
sim::pro essAll();

for(unsigned i=0; i<G. ities.size(); i++)


out << G. ities[i℄.arrivalT << " "; // arrivalD = distan e from origin
out << endl;
}
Abhiram Ranade, 2013. Do not distribute 434

stru t City; // forward de laration, not definition.


stru t Road{
City* toPtr; // Where the road leads to
double length;
Road(City* ptr, double d){toPtr = ptr; length = d;}
};

stru t City{
ve tor<Road> roads;
double arrivalT; // arrival time of first y list
City(){arrivalT = HUGE_VAL;} // not arrived yet.
void arrive(){
if(arrivalT > sim::getTime()){
arrivalT = sim::getTime();
for(unsigned int i=0; i<roads.size(); i++){
sim::post(roads[i℄.length, [this,i℄(){roads[i℄.toPtr->arrive();});
}
}
}
};

stru t RoadNetwork{
ve tor<City> ities;
RoadNetwork( har* infilename) {
ifstream infile(infilename);
int n;
infile >> n;
ities.resize(n);
double dist;
int end1, end2;
while(infile >> end1){
infile >> end2 >> dist;
ities[end1℄.roads.push_ba k(Road(& ities[end2℄,dist));
ities[end2℄.roads.push_ba k(Road(& ities[end1℄,dist));
}
}
};

Figure 25.4: Graph representation


Abhiram Ranade, 2013. Do not distribute 435
File ontent Explanation
6 Number of ities
0 1 450 Kolhapur Mumbai distan e
0 5 300 Kolhapur Satara distan e
1 2 160 Mumbai Pune distan e
1 3 200 Mumbai Nashik distan e
2 3 220 Pune Nashik distan e
3 4 500 Nashik Nagpur distan e
5 2 50 Satara Pune distan e
Figure 25.5: Input le for graph of Figure 25.3
The program uses ommand line arguments. The rst ommand line argument argv[1℄
gives the name of the le whi h ontains data to build the road network. We supply this le
name to a onstru tor of the lass RoadNetwork whi h builds the obje t G for us. The se ond
ommand line argument, argv[2℄ is expe ted to be an integer, and it gives the index of the
origin ity. For this we rst onvert the string argv[2℄ to a stringstream (Appendix F),
and then read from it. Then we start o the simulation.
There is only one kind of event in the simulation: the arrival of a y list into a ity. The
a tions to be taken during the event are pla ed in the member fun tion arrive. To he k if
the arriving y list is the rst y list to arrive into the ity, we examine member arrivalT
in City. If arrivalT is not HUGE VAL, then it has hanged sin e the ity was reated, i.e. the
y list is not the rst to arrive. In this ase, we do nothing. On the other hand, if arrivalT
is still HUGE VAL, then this y list is the rst to arrive, and the following a tions must be
performed.
1. Re ord the orre t arrival time into arrivalT. Note that after this it will no longer be
HUGE VAL.
2. Cy lists must be agged o to leave the ity on ea h outgoing road i. The y list
will rea h the orresponding ity, pointed to by roads[i℄.toPtr, after overing the
distan e roads[i℄.length, i.e. after that mu h time. Hen e, we post an arrival event
for that ity with that mu h laten y.
So this is what the fun tion arrive does.
To start o the simulation, we must ag o the y lists in the origin ity. For this we
post an arrival event at time 0 for the origin ity. After that, main merely waits for all events
to be pro essed, i.e. for all y lists to nish their journey. At the end the earliest time to
rea h ea h ity i from the ity origin an be found in G. ities[i℄.arrivalT. But that is
also the distan e, and so it is printed.

25.5 Con luding Remarks


Dis rete event simulation is a powerful paradigm. Using the lasses developed in this hapter,
you should be able to easily build some modest size simulations. We will see su h an example
in the next hapter.
Abhiram Ranade, 2013. Do not distribute 436
The basi ideas in dis rete event simulation are as follows. Whatever system you wish
to simulate must rst be viewed as a olle tion of intera ting entities. The intera tions
onstitute the events. Ea h event an ause the state of an entity to hange, or ause
additional future events to be posted. We express ea h event as a lambda expression. When
the event happens, the asso iated lambda expression exe utes, and in this exe ution we must
hange the state of the entities in the system or post additional events. Note that the ode
for doing all this ould be pla ed textually inside the lambda expression, as was the ase in
the restaurant and o ee shop simulations. Or inside the lambda expressions we an just
pla e a all to a fun tion whi h auses the state hanges or posting of additional events, as
was the ase in the shortest path algorithm simulation.
The oding style for posting events and a quiring resour es is slightly tri ky. Normally,
when we wish to perform one a tion after another, we write the se ond a tion following the
rst. However, if event A auses event B whi h in turn auses event C, then we would write
the lambda expression of C inside the lambda expression of B whi h in turn ould be in the
lamdba expression of A. Thus although the events happen in su ession, in the ode they
will appear nested. This needs some getting used to.
Note that lambda expressions make it onvenient to express event posting and resour e
a quisition. You should make sure that you understand lambda expressions well, espe ially
variable apture.

Exer ises
1. Modify the restaurant simulation to report how many ustomers left disappointed, how
long after the losing time did the ustomers stay around, the number of ustomers in
the restaurant on the average.
2. Generalize the o ee shop problem so that there are several servers. This is also like
adding a waiting room to the restaurant. You will need to modify resour e. Generalize
the lass so that at most some k lients an be using the resour e simultaneously. You
may nd it easier to do this if you do not keep tra k of whi h lients are using the
resour e, but just keep tra k of how many lients are using the resour e.
3. Suppose every minute a ustomer enters a store with a probability p. Suppose that on
the average ea h ustomer spends t minutes in the store. Then on the average, how
many ustomers will you expe t to see in the store? Little's law from queueing theory
says that this number will be pt. Modify the o ee shop simulation and verify Little's
law experimentally. The law requires that no ustomers are turned away, and that the
average is taken over a long (really in nite) time. So you should remove the apa ity
he ks, and run the simulation for relatively long durations to he k. More ode will
be needed to make all the measurements.
4. Write a simulation of a restaurant in whi h ustomers an arrive in a group, rather
than individually. Suppose a group an have upto 5 members, all sizes equally likely.
Suppose further that tables in the restaurant an a ommodate 4 ustomers, so if
a party of 5 arrives, then two adja ent tables must be allo ated. Thus, the party
must wait if two adja ent free tables are not available. Write a simulation of su h a
Abhiram Ranade, 2013. Do not distribute 437
restaurant. Assume that the tables are in a single line, so tables i; i + 1 are adja ent.
You will have to de ide on how a table will be allo ated if several tables are free: this
will a e t how qui kly you serve parties of 5 members.
5. Have an additional ommand line argument whi h gives the index of a destination ity,
for the shortest path program. Modify the program so that it prints the shortest path
from the sour e to the destination ity, as a sequen e of the numbers of the ities on the
way. Basi ally, in ea h City you must store information about where the rst y list
arrived from. This will enable you to gure out how the shortest path arrives into a
City, re ursively.
6. Modify the shortest path algorithm to use ity names instead of ity numbers in the
input le.
7. Build a simulator for a ir uit built using logi gates. Consider the gates des ribed in
Exer ise 15 of Chapter 6. You should allow the user to build the ir uit on the graphi s
window. You should also allow a delay Æ to be entered for ea h gate. A gate takes as
input values 1 or 0, and produ es output values a ording to its fun tion. However, the
output value is reliably available only after its delay. Spe i ally, suppose some input
value hanges at time t. Suppose this will ause the output value to hange. Then
the new orre t value will appear at the output only at time t + Æ. During the period
from t to t + Æ the value at the output will be unde ned. For this you should use the
value NAN supported as a part of the header le < math>. The value NAN represents
\unde ned value", a tually the name is an a ronym for \Not A Number". This value
behaves as you might expe t: do any arithmeti with it and the result is NAN.
Chapter 26

Simulation of an airport

Suppose there are omplaints about the eÆ ien y of an airport in your ity: say ights get
delayed a lot. Is it possible to pinpoint the reason? Is it then possible to state the best ure
to the problem: that you need to build an extra runway, or some extra gates, or perhaps
just build a ompletely new, bigger airport? A simulation of the airport and how it handles
air raft traÆ an very mu h help in making su h de isions.
The simulation will take as input information about the runways and other fa ilities on
the airport, and about the air raft arriving into the airport from the rest of the world. It
will then determine what happens to the air raft as they move through the airport, what
delays they fa e at di erent points. The average of these delays is perhaps an indi ator of
the eÆ ien y of the airport. To answer questions su h as: how mu h will an extra gate (or
runway or whatever) help, you simply build another simulation in whi h the extra gate is
present, and al ulate the average delay for the new on guration. In addition to textually
des ribing what happens to ea h air raft as it progresses through the airport, it is also
desirable to show a graphi al animation in whi h we an see the air raft landing, taxiing or
waiting at gates. An animation is possibly easier to grasp { perhaps seeing the air raft as
they move might dire tly reveal what the bottlene ks are.
The rst step in building a simulation is to make a omputer model of the relevant aspe ts
of the system being simulated. When you make a omputer model, or a mathemati al model,
of any entity, doubtless you have to throw away many details. A trivial example: the olour
of the airport building is irrelevant as far as its ability to handle traÆ , so that may be
ignored in our simulation. On the other hand, the number of runways in the airport is of
prime importan e, and so annot be ignored. Other fa tors that perhaps annot be ignored
in lude the number of gates at whi h air raft an park to take in and dis harge passengers,
the layout of the taxiways that onne t the runways and the terminals. Other fa tors that
are perhaps less important are the pla ement of auxiliary servi es (e.g. air raft hangars) and
traÆ asso iated with these servi es and how it might interfere with air raft movements. In
general, the more details you in orporate into your model, the more a urate it is likely to
be. However, models with relatively few details might also be useful, if the details are hosen
arefully.
In this hapter, we will build a simulation of a simple airport. The simulation is very
simplisti , but it does address several key problems that arise in su h simulations.

438
Abhiram Ranade, 2013. Do not distribute 439

Figure 26.1: Airport layout with planes


26.0.1 Chapter outline
We will begin by des ribing the spe i ation, i.e. what we plan to simulate. We dis uss the
airport on guration and the (simpli ed) rules under whi h the airport will be deemed to
operate. Then we present an implementation. An important problem in simulating omplex
systems su h as an airport is deadlo k. We dis uss how deadlo ks an be dealt with in real
life and in programs.
The ode for the simulation is given in the simple pp distribution, in simple pp/demos/airport.
Figure 26.1 is a snapshot from its exe ution.

26.1 The simulation model


It is possible to write a simulator whi h simulates airports with arbitrary number of runways,
taxiways, gates and so on. However, for simpli ity, we will onsider the spe i airport
on guration shown in Figure 26.1.
In the gure, the two rossing lines at the top are two runways. The other lines are
taxiways. The long horizontal line near the bottom is the main taxiway, and the nearly
verti al segments on the sides we will refer to as the left and right taxiways respe tively.
There are bran hes going o the main taxiway to the gates. We have not shown the gates,
but they are supposed to be present at the end of these short bran hes. So in this airport
there are meant to be 10 gates, whi h we will number 0 through 9, right to left. The small
Abhiram Ranade, 2013. Do not distribute 440
triangles are meant to represent air raft. As you an see there are three air raft waiting, at
gates 0, 1, and 3, and three others on the runway and taxiways. If you ignore the bran h
taxiways, the runways and the other taxiways onstitute a single long path, starting in the
top left orner, running lo kwise over itself to end in the top right orner. We will all
this the main path. Indeed, for simpli ity, we will require that the main path be used in
the lo kwise dire tion. Thus the runway starting at the top is the landing runway and the
runway ending at the top right is the takeo runway. The bran h taxiways going to the
gates are expe ted to be used in both dire tions.
Our on guration is rather simplisti , ex ept for the interse ting runways. Interse ting
runways are not rare, by the way { in fa t the Mumbai airport has interse ting runways,
whi h is our inspiration for in luding them. But of ourse both the runways in Mumbai
an be used for takeo s as well as landings, and the taxiways and gate pla ements are more
elaborate.
26.1.1 Overall fun tioning
At a high level, the operation of an airport an be des ribed as follows. Ea h air raft lands
and taxies to a gate. The air raft then waits at the gate for a ertain servi e time. After
that the air raft taxies to the runway and takes o . This entire pro ess has to be ontrolled
by the airport authorities so as to ensure safety and eÆ ien y.
26.1.2 Safe operation and half-runway-ex lusion
The gist of the safety requirements is: air raft movement should be planned so that at all
times air raft are well separated from ea h other. A ertain minimum separation is required
even as air raft are taxiing. The separation between air raft must be larger when they are
travelling at high speeds, as will be the ase when they are landing or taking o . The
separation might depend upon the type/size of the air raft. For simpli ity we will assume
that there is just one type of air raft and ignore this issue.
More formally, we will model the safety requirement as follows: we will break runways
and taxiways into segments and require that there be at most one air raft on ea h segment
at any time. Thus by hoosing suÆ iently long segments we an keep the air raft well
separated. Here is the division into segments that we will use. The two runways will be
separate segments, and so will the the left and right taxiways. The main taxiway will be
broken up into segments at the points where the bran h taxiways leave from it. Sin e there
are 10 gates, the main horizontal taxiway will be split into 11 segments. The bran h taxiways
will onstitute separate segments by themselves.
We have an additional ompli ation be ause our two runways overlap. The simplest way
to ensure safe operation would be to say that only one of the runways an be used at any
time. However, to make the problem more interesting and realisti , we will note that the
interse tion is in the initial portion of the runways, and so we will require that the initial
halves of the runways should not be in use simultaneously. In other words, we will require
that if the initial half of the take o runway ontains an air raft then there should be no
air raft in the initial half of the landing runway, and vi e versa. We will all this half-runway
ex lusion.
Abhiram Ranade, 2013. Do not distribute 441
26.1.3 S heduling strategy
The exa t s hedule a ording to whi h air raft land and takeo and even move around while
on the airport is de ided by the air traÆ ontrollers at the airport. They must obey the
safe operation rules and in addition resolve on i ting requests. For example, if two air raft
request permission to use the runway (either for take o or for landing) at the same time,
then permission an be granted to only one. This de ision will have to be taken by the
air traÆ ontrollers. Su h de isions will be made so as to a heive ertain goals, e.g. say
to minimize the average delay, or some weighted average delay with the weights being the
priorities of the di erent air raft.
We will assume that a very simple rst ome rst served s heduling strategy is being
used by the air traÆ ontrollers. Basi ally, ea h air raft requests permission from the
traÆ ontroller for ea h a tion it needs to perform, just as it be omes ready to perform
the a tion. If several air raft ask permissions to perform a tions whi h require a ommon
resour e (say the runway), then permission is granted to the air raft whi h asked earliest,
and the other air raft must wait. Of ourse many other strategies are possible. For example,
we might de ide to give higher priority to landings than takeo s be ause it is easier for a
plane to wait on ground that wait midair! This is explored in an exer ise.
1

26.1.4 Gate allo ation


When an air raft arrives it must be assigned a gate at whi h it is to wait. In general, ea h
air raft may have its preferred gates at whi h it would like to wait. For simpli ity, we will
assume that all air raft an wait at all gates, and say the least numbered free gate will be
allo ated.
Gates an be allo ated anytime after the plane arrives into the airport. We will assume
for de niteness that that gate allo ation must be done just when the air raft is about to
turn into the main taxiway from the right taxiway.
26.1.5 Simulator input and output
The input to the simulator onsists of two number for ea h in oming air raft: the arrival
time, and the servi e time, i.e. the amount of time the air raft needs to wait at a gate. The
simulation will need to have information about how long it takes for an air raft to traverse
the runway and taxiways, but we will onsider this to be a part of the program.
The primary output from the simulator will be: (a) an animation of the air raft as they
enter the airport, move to a gate, halt for the required time, and then take o and leave, (b)
a text re ord of the times at whi h these events happen. When designing an animation, we
need to de ide how frequently will we show the state of our airport. Do we show it every
se ond, or every minute, or only when something interesting happens, e.g. an air raft arrives
or leaves or stops at its gate? For simpli ity, we wil assume the state is to be shown after
every unit time interval, whatever the unit time we de ne in the program.
An air raft must begin its des ent mu h earlier than its landing time, and on e the des ent has begun,
1
the landing annot be postponed in normal ir umstan es. However our rst ome rst serve strategy may
require a ight arrival to be delayed. This is a short oming of our simulation.
Abhiram Ranade, 2013. Do not distribute 442
In addition, we may require several derived outputs. Let us de ne the delay of an air raft
to be the additional time it spent over and above when it ould have departed had the airport
been ompletely empty. So we might be required to ompute the average delay. Su h analyses
and extensions are left to the Exer ises.

26.2 Implementation overview


We will build a dis rete event simulation using the sim lass developed in Chapter 25. The
Resour e lass developed in that hapter will also be useful.
The state of the airport system an be des ribed by the position of the di erent planes
on the di erent taxiways (or gates). So it would seem that these entities must be represented
in our simulation somehow. So we will have a taxiway lass and a plane lass. In addition,
we will also have an ATC lass to represent air traÆ ontrollers. The air traÆ ontrollers
perform operations su h as allo ating gates to planes, and even permitting a plane to move
from one segment to another. Su h ontrol a tions will be implemented in member fun tions
in the ATC lass. The plane lass will basi ally ontain ode that moves the plane forward
when needed.
26.2.1 Safe operation and half-runway-ex lusion
We need to ensure that at most one air raft o upies any taxiway segment at any instant.
Thus it is natural to use the Resour e lass from Chapter 25. We will make ea h taxiway
segment a resour e whi h must be a quired by a plane before it moves onto it. This will
ensure that there is at most one plane on ea h segment.
To implement half-runway-ex lusion we will use the following tri k. Whenever a plane
needs to land or take o , we will require it to reserve a titious halfRW taxiway in addition to
reserving the landing or takeo runways respe tively. After a plane has landed and traversed
half the runway, we want to allow another plane to start taking o . To enable this, we simply
release halfRW as soon as the plane gets to the middle of the landing runway! Same thing
for a plane taking o { it will also release halfRW when it gets to the middle of the takeo
runway.
26.2.2 Gate representation and allo ation
We represent gate G impli itly using bran h taxiway G. Indeed, when a plane has to wait
at gate G it waits at the bottom end of bran h taxiway G. Furthermore, when we want to
allo ate gate G to a plane, we merely reserve bran h taxiway G. With this we an ensure that
at anytime a gate is used only by one plane.
To allo ate a gate we merely examine all the bran h taxiways and determine if any is free,
and if so reserve it. The plane then taxies to the end of that bran h taxiway and waits. After
waiting for the servi e time de ided for the plane, the plane turns around and heads ba k to
the main taxiway. Just as the plane is about to turn onto the main taxiway it releases the
reservation for the bran h taxiway. After this the other planes an use this gate.
Abhiram Ranade, 2013. Do not distribute 443
26.3 Main program and data stru ture
The rst main data stru ture is a ve tor of all taxiway segments and the titious taxiway
halfRW used to implement the half ex lusion rule. Although we simulate an airport with
10 gates, it is onvenient to express the reation using a parameter nGates = 10. You will
see that we need 3*nGates + 6 taxiway segments in luding halfRW. In addition, we will
use an air traÆ ontroller obje t at of type ATC. Obje ts representing air raft are reated
dynami ally as the air raft arrive into the airport. The main program is as follows.
onst int nGates = 10, nSegments = 6+3*nGates;

int main(int arg , har** argv){


initCanvas("Airport Simulator",1000,1000);
ve tor<taxiway*> taxiways(nSegments); // in luding halfRW

onfigure_taxiways_and_runways(taxiways); // reates all taxiways


ATC at (taxiways);
ifstream planeDataFile(argv[1℄);
post_plane_arrivals(at , planeDataFile);

sim::pro essAll();
getCli k();
}
The fun tion onfigure taxiways and runways populates the array taxiways with taxiway
segments. We dis uss this fun tion in the next se tion, whi h also dis usses the taxiway
lass in detail. After this the main program reates an obje t at to represent air traÆ
ontrollers. Finally, the fun tion post plane arrivals reates plane arrival events. After
this sim:pro essAll is alled and the simulation unfolds.
The fun tion post plane arrivals takes the plane data from a le whi h is required to
be supplied as the rst ommand line argument to the main program. The reated events
will all the pro essArrival member fun tion of at . This all will reate the plane obje ts.
The plane lass is dis ussed later.
void post_plane_arrivals(ATC &at , ifstream &planeDataFile){
int arrivalT, servi eT;
while(planeDataFile >> arrivalT){
planeDataFile >> servi eT;
sim::post(arrivalT, [=,&at ℄(){at .pro essArrival(arrivalT, servi eT);});
}
}

26.4 The taxiway lass


Instan es of the taxiway lass must serve two purposes: they must be visible on the s reen
as lines, and the planes must be able to reserve them. So it is natural to derive the taxiway
lass from the Line lass and the Resour e lass of the pre eding hapter.
Abhiram Ranade, 2013. Do not distribute 444
lass taxiway : publi Line, publi Resour e{
publi :
int traversalT; // time needed to traverse the taxiway
double stepsize; // distan e overed per time step
taxiway(float xa, float ya, float xb, float yb, int trT)
: Line(xa,ya,xb,yb), traversalT(trT),
stepsize(sqrt(pow(xa-xb,2)+pow(ya-yb,2))/traversalT) {}
};

The taxiway onstru tor rst reates the Line representing the taxiway on the s reen.
Ideally we should distinguish the on-s reen line from the real taxiway, and provide details
about the real taxiway separately. For simpli ity we have assumed that the on-s reen taxiway
and the real taxiway will have same oordinates on the s reen as well as the ground (say the
units have been onveniently sele ted). In onstru ting a taxiway we also provide the time
required to traverse it in some hypotheti al time units. Sin e we know the length of the
taxiway we al ulate how mu h an air raft moves forward ea h (hypotheti al) step when on
this taxiway { this information is needed to perform the animation.
Note that the Resour e onstru tor is not expli itly alled, so a all with no arguments
will be inserted by the ompiler. This will set the member inUse of the taxiway (derived
from Resour e, Se tion 25.3) to NULL, indi ating that initially the taxiway is unreserved.
The fun tion onfigure taxiways and runways will instantiate taxiways to reate the
main path and the bran h taxiways. As mentioned earlier, the onstru tion is des ribed
in terms of a onstant nGates = 10 denoting the number of gates. The initial nGates+5
elements of taxiways respe tively represent the landing runway, the right taxiway, the
nGates+1 segments of the main taxiway, the left taxiway, and the takeo runway (Fig-
ure 26.2). The nGates subsequent elements will represent the bran h taxiways going toward
the gates, and the next nGates elements will represent the bran h taxiways oming ba k
from the gates. Then we will have one more segment representing the titious taxiway
halfRW.
The ode below reates the taxiway elements along with their geometri al oordinates for
display purposes. The names RW1X1 et . are onstants indi ating the geometri oordinates
of the appropriate taxiways, and the names tRW et . are onstants indi ating the time to
traverse the appropriate taxiways.
void onfigure_taxiways_and_runways(ve tor<taxiway*> &taxiways){
taxiways[0℄ = new taxiway(RW1X1,RW1Y1,RW1X2,RW1Y2,tRW); // landing runway
taxiways[1℄ = new taxiway(RW1X2,RW1Y2,TWX1,TWY1,tVT); // right taxiway

float twXdisp = ((float)TWX2-TWX1)/(nGates+1);


float twYdisp = ((float)TWY2-TWY1)/(nGates+1);

for(int i=0; i<= nGates; ++i){ // main taxiway: 11 segments


taxiways[2+i℄ = new taxiway(int(TWX1+i*twXdisp), int(TWY1+i*twYdisp),
int(TWX1+(i+1)*twXdisp),
int(TWY1+(i+1)*twYdisp), tMT);
}
Abhiram Ranade, 2013. Do not distribute 445
taxiways[3+nGates℄ = new taxiway(TWX2,TWY2,RW2X1,RW2Y1,tVT); // left taxiway
taxiways[4+nGates℄ = new taxiway(RW2X1,RW2Y1,RW2X2,RW2Y2,tRW);
// takeoff runway

for(int i=0; i<nGates; ++i){ // bran h to gate


taxiways[5+nGates+i℄ = new taxiway(int(TWX1+(i+1)*twXdisp),
int(TWY1+(i+1)*twYdisp),
int(TWX1+(i+1)*twXdisp), TWYT, tBT);
}
for(int i=0; i< nGates; ++i){ // bran h from gate
taxiways[5+2*nGates+i℄ = new taxiway(int(TWX1+(i+1)*twXdisp), TWYT,
int(TWX1+(i+1)*twXdisp),
int(TWY1+(i+1)*twYdisp), tBT);
}
taxiways[5+3*nGates℄ = new taxiway(0,0,0,0,0); // halfRW
}

It will be onvenient to de ne the following onstants.


onst int toGates = 5+nGates, fromGates = 5+2*nGates, halfRW = 5 + 3*nGates;
landing = 0, rightTaxiway = 1,
leftTaxiway = toGates-2, takeOff = toGates-1;
The taxiway numbering vis-a-vis gate numbering is shown in Figure 26.2. We have shown
the taxiway going to a gate as being distin t from the taxiway going ba k from the gate.
This is only for the onvenien e of drawing; physi ally they are oin ident.

26.5 The ATC lass


The ATC lass instan e at represents the air traÆ ontrollers. The at ontrols the plane
movements, starting from pro essing plane arrival in whi h the plane obje ts are reated.
The lass ontains member fun tions pro essArrival, grantClearan e and allo ateGate
for these operations.
lass ATC{
ve tor<taxiway*> &taxiways;
int planeId; // to number planes as they get generated
publi :
ATC(ve tor<taxiway*> &tw) : taxiways(tw), planeId(0) {}
void pro essArrival(int arrivalT, int servi eT);
void grantClearan e(plane *p, int segment, int &gate);
void allo ateGate(plane* p, int segment, int &gate);
};
The pro essArrival fun tion reates plane obje ts. After that, for ea h reated plane
obje t, the fun tion a quires the runway and halfRW. After that, the plane is asked to move
Abhiram Ranade, 2013. Do not distribute 446

leftTaxiway
rightTaxiway+1+G rightTaxiway

G ... 1 0
fromGates + G toGates + G

Figure 26.2: Gate and segment numbering

on the taxiway segment representing the landing runway. As will be seen in Se tion 26.6,
the ATC lass is a friend of the plane lass. Thus the fun tions in the ATC lass an a ess
the data members id, arrivalT, servi eT segment and gate in the plane lass. As will be
seen, these respe tively denote the plane's identifying number, the arrival time, the servi e
time, the segment on whi h the plane is urrently, and the gate allo ated to the plane if any.
void ATC::pro essArrival(int arrivalT, int servi eT){
plane *p = new plane(++planeId, arrivalT, servi eT, taxiways, *this);
taxiways[landing℄->a quire([=℄(){
taxiways[halfRW℄->a quire([=℄(){
sim::log()<< "Plane " << p->id << " lands. s heduled arrival "
<< p->arrivalT << ", Servi e time " << p->servi eT << endl;
p->show(); // make the plane visible on the s reen
p->prepareToMove(landing);
});
});
}
The movement of a plane on a single taxiway segment is implemented by the fun tions
prepareToMove and moveOnSegment in the plane lass. During the movement when the
plane omes to the end of a taxiway segment, it will need to know from the at what segment
to move on next (e.g. whether to turn on a bran h taxiway) and also ask that the segment
be reserved. For this, the plane will all the grantClearan e member fun tion of ATC. After
grantClearan e nishes its work, the plane is ready to move, and so plane::prepareToMove
Abhiram Ranade, 2013. Do not distribute 447
an be alled again.
The fun tion grantClearan e determines where to dire t the plane next and what re-
sour es to reserve for it, based upon the plane position, i.e. the segment on whi h the plane
is, and whi h gate the plane has been allo ated.
void ATC::grantClearan e(plane *p){
if(p->segment == rightTaxiway)
allo ateGate(p);
else if(p->segment == rightTaxiway + 1 + p->gate){
taxiways[p->segment℄->release();
p->prepareToMove(toGates + p->gate);
}
else if(p->segment == toGates + p->gate){
sim::log()<< " Plane " << p->id << " at gate " << p->gate
<< " will wait for " << p->servi eT << endl;
sim::post(p->servi eT, [=℄(){ // wait for servi e
p->prepareToMove(fromGates + p->gate);
});
}
else if(p->segment == fromGates + p->gate){
taxiways[rightTaxiway + 2 + p->gate℄->a quire([=℄(){
taxiways[toGates + p->gate℄->release();
p->prepareToMove(rightTaxiway + 2 + p->gate);
});
}
else if(p->segment == leftTaxiway){
taxiways[takeOff℄->a quire([=℄(){
taxiways[halfRW℄->a quire([=℄(){
taxiways[leftTaxiway℄->release();
p->prepareToMove(takeOff);
});
});
}
else if(p->segment == takeOff){
taxiways[takeOff℄->release();
p->hide();
sim::log() << " plane " << p->id << " left." << endl;
delete p;
}
else { // default ase
taxiways[p->segment+1℄->a quire([=℄(){
taxiways[p->segment℄->release();
p->prepareToMove(p->segment+1);
});
}
}
Abhiram Ranade, 2013. Do not distribute 448
If p->segment equals rightTaxiway, then the plane is at the end of the right taxiway.
So a gate must be reserved for it. As dis ussed earlier, reserving gate G is equivalent to
reserving bran h taxiway towards gate G, i.e. taxiway toGate + G (Se tion 26.2.2, also see
Figure 26.2). This is done by the fun tion allo ateGate whi h we dis uss later. After the
gate allo ation is done, allo ateGate will signal the plane to move forward.
If p->segment equals rightTaxiway + 1 + p->gate, then we know that the plane has
overed 1 + p->gate segments of the main taxiway, and is thus at the right position to
turn towards the gate allo ated to it (Figure 26.2). Furthermore, taxiway segment toGate
+ p->gate has already been reserved for it. Thus it an relese the urrent segment on whi h
it is, and start moving on segment toGate + p->gate.
If p->segment equals toGate + p->gate, then we know that the plane is at the bottom
end of the bran h taxiway. Here it must wait for its stipulated servi e time, i.e. p->servi eT.
After this, it an start moving on the segment going ba k to the taxiway, i.e. segment
fromGate + p->gate.
If p->segment equals fromGate + p->gate, then we know that the plane has returned
ba k to the main taxiway after waiting at the gate. So now we must a quire the next
segment of the main taxiway, i.e. segment rightTaxiway + 2 + p->gate. After that we
must release the gate, i.e. segment toGate + p->gate so that other planes an use the gate.
And after this, we an start moving on segment rightTaxiway + 2 + p->gate.
If p->segment equals leftTaxiway, then the plane is about to take o . So we must
reserve the takeo runway, and halfRW. After that we release the left taxiway, and we an
start moving on the takeo runway.
If p->segment equals takeOff, then the plane has nished takeo . So we must now hide
it, and re laim the memory given to it.
If p->segment has none of the above values, then no spe ial a tions are needed. The
plane merely needs to move into the next segment, whi h must be reserved for it. Then the
urrent segment on whi h the plane is, must be released. The plane is then asked to move
to the reserved segment. This is the default ase, given at the bottom of grantClearan e.
Finally we dis uss the fun tion allo ateGate.
void ATC::allo ateGate(plane* p){
p->gate = -1; // means not allo ated.
for(int i=0;i<nGates;++i){
if (taxiways[toGates + i℄->reserve()){
p->gate = i;
break;
}
}
if(p->gate >= 0) // if gate allo ation su eeded
taxiways[p->segment+1℄->a quire([=℄(){
taxiways[p->segment℄->release();
p->prepareToMove(p->segment+1);
});
else
sim::post(1,[=℄(){allo ateGate(p);}); // else try again
}
Abhiram Ranade, 2013. Do not distribute 449
The gate allo ation pro edure as dis ussed earlier is simple: we reserve the smallest numbered
unreserved gate. If reservation is su essful, then we try to move forward. For this, we a quire
the next segment. When that is a quired, we release the urrent segment, and then try to
move on the new segment. If gate reservation is not su essful, then we try reservation again
after one step.

26.6 The plane lass


The air raft are implemented using a plane lass. An air raft must appear on the s reen as
a part of the animation. So we inherit from the Turtle lass. Indeed, our air raft appear
on the s reen as turtles. We ould have de ned a more air raft like visual appearan e by
using the polygon lass, but that is left for the exer ises. To keep tra k of whi h taxiway
segment the plane is on at any time instant we will have a data member segment. We will
have another data member timeToSegmentEnd, in whi h we keep tra k of the number of
steps we need to move forward in order to rea h the end of the urrent segment. In addition,
we need to note the gate allo ated for the air raft. For this we use an integer data member
gate. Finally, the plane will need to know about the taxiways and the at , so we have data
members to hold those referen es.
lass plane : publi Turtle {
publi :
int id; // identifying number for plane
int arrivalT; // arrival time
int servi eT; // how long the air raft waits at the gate
int segment; // index of taxiway segment the air raft is on
int timeToSegmentEnd; // how far from the end of the segment
int gate; // id of allo ated gate
ve tor<taxiway*> &taxiways;
ATC &at ;
publi :
plane(int i, int at, int st, ve tor<taxiway*> &tw, ATC &at 0)
: id(i), arrivalT(at), servi eT(st), taxiways(tw), at (at 0) {
hide();
penUp();
gate = -1; // indi ates gate not allo ated
}
void prepareToMove(int newsegment);
void moveOnSegment();
friend lass ATC;
};

Note that we have made the ATC lass a friend be ause it needs to know where a plane is
et . A plane is reated in the ATC lass as dis ussed earlier.
The basi a tion performed by a plane is moving on a taxiway. When the at determines
that a plane must move on ertain segment of the taxiway, it alls the prepareToMove
Abhiram Ranade, 2013. Do not distribute 450
member fun tion of the plane lass. This does minor housekeeping and aligns the plane with
the dire tion of the taxiway. The data member timeToSegmentEnd is also set to the number
of steps in whi h the urrent segment is to be traversed. After that the plane is ready to
move.
void plane::prepareToMove(int newSegment){
segment = newSegment;
Position linestart = taxiways[segment℄->getStart();
moveTo(linestart.getX(), linestart.getY());
Position lineend = taxiways[segment℄->getEnd();
fa e(lineend.getX(), lineend.getY());
timeToSegmentEnd = taxiways[segment℄->traversalT;
sim::post(0, [=℄(){this->moveOnSegment();});
}
At the end, the moveOnSegment member fun tion is alled. This auses the plane to take
one step on the segment taxiway. To traverse the entire segment, the fun tion is alled
repeatedly, for ea h value of timeToSegmentEnd as it is de remented down to 0. At the end,
the plane has rea hed the end of the segment, and so learan e must be sought from the air
traÆ ontrollers for future a tion. So at .grantClearan e is alled.
There is one slight ompli ation to be handled: when the plane is taking o or landing,
then the taxiway halfRW must be released when the plane has rea hed the middle of the
segment.
void plane::moveOnSegment(){
if(timeToSegmentEnd != 0){
if((segment == landing || segment == takeOff)
&& timeToSegmentEnd == taxiways[segment℄->traversalT/2){
taxiways[halfRW℄->release();
}
forward(taxiways[segment℄->stepsize);
--timeToSegmentEnd;
sim::post(1, [=℄(){moveOnSegment();});
}
else
at .grantClearan e(this);
}

26.7 Deadlo ks
A deadlo k is a te hni al term used to des ribe a system in whi h one entity e is waiting
1
to reserve a resour e held by entity e whi h in turn is waiting to reserve a resour e held by
2
and entity e and so on, till some entity en in this sequen e is waiting to reserve a resour e
3
held by e . Noti e that in this ase no entity an make progress, be ause all are waiting for
1
ea h other. As an example, Figure 26.7 shows ars deadlo ked on roads in a ity. Note that
the roads are one ways, as shown. The ars in the top road are waiting for the spa e ahead
Abhiram Ranade, 2013. Do not distribute 451

Figure 26.3: TraÆ deadlo k in a ity


of them to be ome empty. This will happen if the ars in the right road an move down.
But these an move down if the ars in the bottom road an move left. These in turn will
move left only if the ars in the left road an move. But these are blo ked be ause of the
ars in the top row. The net result: no one an move. Deadlo k.
A deadlo k is possible on a ir ular taxiway if every segment ontains a plane whi h wants
to move forward. In our airport it would seem that the taxiways do not form a ir ular path.
However we have to be areful in implementing the half-runway-ex lusion rule.
It turns out that deadlo ks will not arise be ause we observe the following dis ipline in
reserving halfRW. A landing air raft must rst reserve the landing runway and only then
halfRW. Similarly a plane taking o must rst reserve the takeo runway and only then
halfRW. You an see that this is a good strategy: halfRW being a pre ious resour e must
be reserved last. If a plane reserves halfRW and annot reserve the landing runway, then
it prevents take o s unne essarily until su h time as it reserves the landing runway. More
formally, as the exer ise asks you, you should be able to prove that if this poli y is used
there an be no deadlo k. On the other hand, if landing planes as well as planes taking o
reserve halfRW rst, then it is possible to reate a deadlo k by arefully onstru ting the
arrival sequen e of the planes. The exer ises invite you to explore this possibility.

26.8 Con luding remarks


There are many ways in whi h we ould have designed this program. For example, note that
the lass ATC does not ontain any interesting data members. Thus you might hoose not
Abhiram Ranade, 2013. Do not distribute 452
to have this lass at all and instead in lude the member fun tions from this lass into the
plane lass itself. This would simplify the ode a bit; you ould dire tly a ess the members
in plane in writing fun tions su h as ATC::pro essArrival. However, we have preferred to
have two lasses be ause we felt it is better to put air traÆ ontrol a tions in an ATC lass.
Another possibility is to not use the sim and Resour e lasses at all. Write the ode
from the point of view of the air traÆ ontrollers who examine the planes at ea h step and
advan e them as needed. You are asked to do this in an exer ise.

Exer ises
1. Modify the simulation program to print out the average air raft delay.
2. De ne a better plane lass in whi h the on s reen image looks like an air raft rather
than a triangle.
3. Suppose we wish to ensure that as mu h as possible, an air raft must land at its arrival
time. Thus, while granting halfRW to a departing plane, we must he k whether no
plane will want to land during the interval in whi h the departing plane will use halfRW.
Devi e a good me hanism to do this. Hint: perhaps you an reserve the landing runway
and halfRW a bit earlier than needed?
4. The program given in the text uses so alled busy waiting to allo ate gates, i.e. if a
gate is not urrently available, the plane retries after 1 step. It will be more eÆ ient
if the plane an await the release of any gate. Develop a lass to represent su h a
resour e group. A resour e group models a sequen e of obje ts, ea h of whi h an be
either reserved or unreserved. On a reserve request, one of the unreserved obje ts
must be allo ated, i.e. the requesting entity should be set as its owner. If all obje ts
are urrenly reserved, then the reserve request is deemed to fail and should thus return
false. In that ase the entity may await its release. When any of the obje ts be omes
available, that should get reserved for the waiting entity. Use this in the simulation
ode.
5. Show that our strategy of reserving resour es ensures that there is no deadlo k. Spe if-
i ally, show that at every step some air raft will make progress, and that there will
not exist entities e ; : : : ; en where ei is waiting for a resour e urrently held by entity
0 1
ei
+1 mod n.

6. Suppose we reserve halfRW rst and then the take o or landing runways. Constru t
an input sequen e (the le arrivals.txt) su h that there is a deadlo k.
7. Perform the airport simulation without using the sim and Resour e lasses, as de-
s ribed in Se tion 26.8. Do you think this will run faster than the simulation we have
presented, or slower? What if there is no need to produ e a graphi al output, i.e. only
a textual re ord is required?
8. Suppose we do not want to divide the taxiway into segments. Instead, suppose we
will allow a plane to move a ertain stepsize at ea h step while keeping a ertain safe
Abhiram Ranade, 2013. Do not distribute 453
distan e behind the plane ahead, if any. Implement this. The other rules must still
be followed, i.e. the half-runway-ex lusion rule and the rule that there an be at most
one air raft on ea h runway at any instant. Also, there an be only one air raft on any
bran h taxiway.
9. Simulate an airport with 2 runways that do not interse t. Assume the same traÆ as
that for an airport with interse ting runways. De ne the delay of an air raft as the
a tual time it spends on the airport less the time it would spend if no other air raft
was present in the airport. Compute the total delay for all air raft in both models.
In rease the traÆ i.e. arrivals per unit time and see how the total delay hanges for
the interse ting and non-interse ting runways.
10. If an air raft is not allowed to land when it arrives at the airport, it must y in a
ir ular path of total duration some T and then try again. This is a more realisti
model than what we have in the text. Simulate this model.
11. Consider the shortest path algorithm of Se tion 25.4. Suppose that we are also given
the geometri oordinates for ea h vertex of the graph. Show a visual simulation of
the algorithm, i.e. a turtle should move along ea h edge as if it were a y list.
Chapter 27

Non-linear simultaneous equations

Suppose you want to onstru t a parallelopiped box of volume 1010 m , surfa e area 700 3

m and having a base whose diagonal is 22 m. What are the lengths of the sides of the box?
2

If u ; u ; u denote the side lengths in m, learly we have u u u = 1010, 2(u u + u u +


1 2 3 1 2 3 1 2 2 3
u u ) = 700 and u + u = 22 . We have 3 equations in 3 unknowns, but unfortunately these
3 1
2 2 2

equations are non-linear! In Se tion ?? we saw how to solve linear simultaneous equations,
1 2

but this problem is mu h more diÆ ult. Indeed it is fair to say that solving non-linear
simultaneous equations is bit of an art. While, there is no single guaranteed method for
solving non-linear equations in many variables, there are some strategies whi h seem to
often work. On e su h strategy is the Newton-Raphson method (NRM). We have already
studied NRM in Se tion 8.4 for the one dimensional ase. Its generalization to multiple
dimensions is pre isely what we need and we will study it in this hapter.
After studying NRM for multiple dimensions, we will onsider a more elaborate problem:
given a hain of links of di erent lengths, ompute the on guration in whi h it hangs if
suspended from some xed pegs. We will see that NRM solves this problem ni ely.
The exer ises give more appli ations of NRM in multiple dimensions.

27.1 Newton-Raphson method in many dimensions


In one dimension, NRM is used to nd the root of a fun tion f of one variable, i.e. nd u
su h that f (u) = 0. The higher dimensional ase is a natural generalization. We are now
given n fun tions f ; : : : ; fn ea h of n variables, and we want to nd their ommon root, i.e.
1
a set values u ; : : : ; un su h that fi(u ; : : : ; un) = 0 for all i.
1 1
As you might see, this is really the same as solving simultaneous, possibly non-linear
equations. Any equation in n unknowns an be written so that the right hand side is 0, but
then we an treat what is on the left hand side as a fun tion of the unknowns. Indeed, our
equations for the box problem an be stated in this form as follows:
f (u ; u ; u ) =
1 1 2 3 u u u 1010 =0 1 2 (27.1)
3

f (u ; u ; u ) = 2(u u + u u + u u ) 700 = 0
2 1 2 3 1 2 2 (27.2)
3 3 1

f (u ; u ; u ) =
3 1 2 3 u + u 484 =0 2
1 (27.3) 2
2

Indeed the ommon root u = (u ; u ; u ), of f ; f ; f will pre isely give us the side lengths
1 2 3 1 2 3
of the box we want to onstru t.
454
Abhiram Ranade, 2013. Do not distribute 455
An important point to be noted is that ea h fun tion fi an be thought of as the error
for the orresponding equation. Our goal in solving the equations is to make the error zero.
Note that in this interpretation the errors an be positive or negative.
As in one dimension, NRM in many dimensions pro eeds iteratively. In ea h iteration,
we have our urrent guess for the values of the unknowns. We then try to nd by how mu h
ea h unknown should hange, so that we (hopefully) get loser to the root. We then make
the required hange in the unknowns, and that be omes our next guess. We he k if we our
new values are lose enough to the ( ommon) root. If so, we stop. Otherwise we repeat. We
will use u ; : : : ; un to denote the unknowns. Let their urrent values be u ur ; : : : ; un ur. Our
1 1
goal is to determine what in rements u ; : : : ; un to add to these values so as to get our 1
next guess u next; : : : ; unnext.
1
We will use our box problem as a running example for explaining the method. Suppose
for this problem we have guessed u ur = 20, u ur = 10 and u ur = 5. Then we have
1 2 3
f (u ur ; u ur ; u ur ) = 10, f (u ur ; u ur ; u ur ) = 0, f (u ur ; u ur ; u ur ) = 16,
1 1 2 3 2 1 2 3 3 1 2 3
For a minute onsider that we only want to make f be ome 0, and we only an hange 1
u . Now this is simply the one dimensional ase. If we make a small in rement u in
1 1
u , we know that f will hange in proportion to u and the derivative of f with respe t
1 1 1 1
to u . A tually, sin e f is a fun tion of many variables, all of whi h we are keeping xed
1 1
ex ept for u , we should really say, \the partial derivative
1 of f with respe t to u ". Thus the 1 1
(additive) hange f in f will be approximately uf u . Further, the partial derivative
1 1
1
1
must be evaluated at the urrent values, so we will write: 1


f1
f  1 u
u1 ur 1
(27.4)
But we want f next = f ur + f to be ome
1 zero,
so perhaps we should hoose f =
1 1 1

f ur = 10. Further, we know that u
1 = u u = 50. Thus we have:
f 1
1 2 3
ur ur

10  50u 1

So we indeed hoose u = = 0:2. The new value of u be omes 20+0.2=20.2, and


1
10
1
the new value of f be omes 20:2  10  5 1010 = 0. In this ase, the error in the rst
50
1
equation has ompletely vanished. Things will not be this good in general, but as you might
remember from Se tion 8.4 that we an expe t f to get loser to 0 than it was. 1
But of ourse, nothing really for es us to only hange u . Thus, if we are allowed to vary 1
all the variables, then equation 27.4 generalizes as: 1

Think about hanging 1 rst, and then 2 and so on. Initially we are at ( 1 ur 2 ur 3 ur ). After
1 u u u ;u ;u

hanging 1 by get
to the point whi h we will all ( 1 ur 2 ur 3 ur ). In this movement, we have hanged
u u 0; u 0; u 0

1 by about u1  1. From the new point we hange 2 by  2. The hange that this auses in 1 is
f1
f u u u f
ur
about f1
u2  2 total hange in 1 is approximately
u f
ur0

1+ 
 f1  f1
u u2

 u1  u2
ur ur0

But the values at ur and ur


0
are nearly the same, assuming  1  2 are small. u ; u
Abhiram Ranade, 2013. Do not distribute 456

f1
f1 f1
f1  + u u
u1 ur 1 u2 + u u3 (27.5)
2 ur 3 ur

Again, we want f1 = f1 ur , and try to pi k  u1; u2; u3 to satisfy


f f f
f1 ur = 1 u1 + 1 u2 + 1 u3 (27.6)
u1 ur u2 ur u3 ur
In a similar manner we will require the following as well.
f f f
f ur = u + u u + u u
2 2
(27.7) 2
2
u ur 1 ur
1
2 ur
2
3
3

and
f f f
f ur = u + u u + u u
3 3
(27.8) 3
3
u ur 1 ur
1
2 ur
2
3
3

Noti e now that u ; u ; u are the only unknowns in Equations (27.6,27.7,27.8), and in
1 2 3
these variables the equations are linear! Thus we an solve them. Evaluating the urrent
values of the fun tions and the partial derivatives we get:
10 = 50u + 100u + 200u
1 2 (27.9) 3

0 = 30u + 50u + 60u 1 2 (27.10)


3

16 = 40u + 20u 1 2 (27.11)


Solving this we get (u ; u ; u ) = ( 0:52; 0:24; 0:06). So we have (u next; u next; u next =
1 2 3 1 2 3
(19:48; 10:24; 5:06). For these values we see that (f ; f ; f ) = (0:655554; 0:283244; 0:327963),
1 2 3
whi h taken together are mu h loser to zero than (10; 0; 16).
27.1.1 The general ase
In general we will have n equations:
X fi
fi (u ur ; : : : ; un ur ) = uj (27.12)
1
u j j ur

We solve these to get (u ; : : : ; n), and from these we an al ulate ujnext = uj ur + uj ,
1
for all j .
It is ustomary to onsider the above equations in matrix form. De ne an n  n matrix

A in whi h aij = u
fi
j
uj . De ne an n element ve tor b where bi = fi (u ur ; : : : ; un ur). 1

Let u denote the ve tor of unknowns (u ; : : : ; un). Then the above expressions an be
ur
1
written in the form
A(u) = b
in whi h A; b are known and we solve for u. The matrix A is said to be the Ja obian
matrix for the problem. Further, it is ustomary to de ne ve tors u ur = (u ur ; : : : ; un ur) 1
and unext = (u next; : : : ; unnext). Then our next guess omputation is simply:
1

unext = u ur + u
Next we omment on when we should terminate the pro edure, and how to make the
rst guess.
Abhiram Ranade, 2013. Do not distribute 457
27.1.2 Termination
We should terminate p the algorithm when all fi are lose to zero. A standard way of doing this
is to require that f +    ; fn be ome smaller than some  that we hoose, say  = 10
2 2 7

if we use float, and even smaller if we use double to represent our numbers. In keeping
1

with
p our interpretation that fi is the error, the quantity (f ; : : : ; fn ) is the ve tor error, and
1
f +    ; fn is the 2-norm or the Eu lidean length of the ve tor error.
2
1
2

27.1.3 Initial guess


Finding a good guess to start o the algorithm turns out to be tri ky. In one dimension,
we roughly plotted the fun tion and sought a point lose enough to the root. In multiple
dimensions, this is more diÆ ult.
Newton's method works beautifully if we are already lose to the root. This is be ause
very lose to the root, the equations su h as Equation (27.6) be ome very a urate. One
idea is to try to satisfy the equations approximately. It is often enough to satisfy only
some of the equations. For example, we found for the box problem that a starting guess of
(u ; u ; u ) = (9; 10; 11) work quite well. Note that these numbers satisfy Equation 27.1 very
1 2 3
losely.
On the other hand, an initial guess of (1,2,3) worked quite badly: it produ ed the \an-
swer" (2.2659 -21.883 -20.3692). Note that this satis es the equations losely, but surely we
annot have negative side lengths! This points to another feature of non-linear equations:
there may be multiple roots. Your iterative pro edure may not ne essarily take you to the
orre t one.
In the next se tion, we will have more to say on this.

27.2 How a ne kla e reposes


Suppose you are given a hain of n links, where the ith link has length Li , i = 0; : : : ; n 1.
Say the hain is hung from pegs at points (x ; y ) and (xn; yn) whi h are known. What is
0 0
the shape attained by the hain when it omes to rest, hung in this manner? The links in
the hain need not have equal lengths.
27.2.1 Formulation
Let xi ; yi denote the oordinates of the left endpoint of link i, and of ourse xi ; yi are
+1 +1
then the oordinates of the right endpoint, where i = 0; : : : ; n 1. As dis ussed above, we
already know the values of (x ; y ) and (xn; yn), these are the oordinates of the pegs from
0 0
whi h the hain is suspended. The other xi ; yi are the unknows we must solve for. We are
given the lengths Li of the links, thus the variables xi; yi must satisfy the following equations.
(xi xi ) + (yi yi) Li = 0
+1
2
+1
2 2
(27.13)
We also need to onsider the for es on the links. Suppose that Fi is the (ve tor) for e
exerted by link i 1 on link i (F is the for e exerted on link 0 by the left peg, and Fn is
0 1
the for e exerted by link n 1 on the right peg). Note of ourse that by Newton's third law,
Abhiram Ranade, 2013. Do not distribute 458
if one obje t exerts a for e F on another, the latter exerts a for e of F on the former. So
ea h link i has a for e Fi a ting on its left endpoint, and a for e Fi a ting on its right
+1
endpoint. Further, there is its weight, Wi, also ve tor, whi h a ts at its enter. When the
hain is at rest, total for e on ea h link must be zero, as well as the total torque.
Thus for ea h link we have Fi Fi + Wi = 0. Suppose Fi = (hi ; vi), i.e. hi and
+1
vi are the horizontal and verti al omponents of Fi . Be ause Wi is only verti al, we an
write it as Wi = (0; wi). The weight a ts downwards, so perhaps we should write wi as
the y omponent. However, do note that in the oordinate system of our graphi s s reen y
in reases downwards. Hen e we do not have the negative sign. Further, we will assume that
the weight is proportional to the length, and so we will write wi = Li . Now balan ing the
horizontal omponent we get hi hi = 0, i.e. all these variables are identi al! Thus we
+1
ould write a ommon variable h instead of them. Balan ing the verti al omponent we get,
for all i:
vi vi + Li = 0
+1 (27.14)
Finally we need to balan e the torque as well. For this we need to onsider the right endpoint
to be the enter. Remember that the torque due to a for e F equals the magnitude of the
for e times the perpendi ular distan e from the enter to the line of the for e. The torque
due to the horizontal omponent of Fi is simply the horizontal omponent times the verti al
distan e to the horizontal omponent. Thus it is hi (yi yi) = h(yi yi). This torque is
+1 +1
in the lo kwise dire tion. The torque due to the verti al omponent is similar, vi (xi xi ),
+1
but in the ounter lo kwise dire tion. The distan e to the line of the weight is (xi xi )=2,
+1
and so the torque due to it is Li (xi xi)=2, also in the ounter lo kwise dire tion. But
+1
the total torque, onsidered in say the lo kwise dire tion, must be zero. Thus we get:
h(yi
+1 yi) vi (xi +1 xi ) Li (xi xi )=2 = 0
+1 (27.15)
Equations (27.13), (27.14), and (27.15) apply to ea h link, and thus we have 3n equations over
all. The unknowns are x ; : : : ; xn (noting that x ; xn are known) and similarly y ; : : : ; yn ,
1 1 0 1 1
and h, and v ; : : : ; vn. Thus there are a total of (n 1)+(n 1)+1+(n +1) = 3n unknowns.
0
Thus the number of unknowns and the number of equations mat h; however, our equations
(27.13) and (27.15) are not linear. So we need to use the Newton Raphson method.
27.2.2 Initial guess
Making a good initial guess is vital for this problem.
To make a good guess, we have to make use of our \ ommon sense" expe tation about
what the solution is likely to look like. For the ne kla e problem, we an expe t that the
ne kla e to hang in the shape of a \U". So presumably we an set (xi ; yi) along a semi ir le
whi h hangs from the pegs. Also we an arrange the for e values so that the total verti al
for e on ea h link is 0. One way to do this is to ompute the total weight, and set v ; vn to
0
bear half of it. On e we set this the other values of vi an be set as per Equations (27.14).
The horizontal for e h ould be set to 0 to begin with. It is mu h tri kier to try to balan e
the torque. But it turns out that the initial values as we have outlined here are enough to
produ e a good answer.
Abhiram Ranade, 2013. Do not distribute 459
27.2.3 Experien e
We oded up the algorithm and set the initial values as per the guessing strategy des ribed
above. We then ran the algorithm. After ea h iteration, we plotted the ne kla e on guration
on our graphi s s reen. As you an see, the on guration qui kly seems to rea h a stable
point. Indeed, we also printed out the square error, and it got lose to zero fairly qui kly.

27.3 Remarks
As you experiment with NRM you might noti e that the error norm (as de ned in Se -
tion 27.1.1) does not ne essarily de rease in ea h iteration. This is understandable, the error
norm is guaranteed to de rease only if the equations su h as (27.6) hold exa tly.
It is possible to show, however, that the ve tor u does indeed give the exa t dire tion
in whi h to move from u ur for whi h the rate of redu tion of the error norm is the largest
possible. Thus there exists an su h that the error norm at u ur + u will be stri tly
smaller than that at u ur . We an try to roughly nd this by starting with = 1 (whi h
is equivalent to taking the full step, ie. the basi NRM), and su essively halving it till we
nd a point u ur + u where the error norm is lower than at u ur .

27.4 Exer ises


1. Write the program to solve the box problem.
2. Write the program to solve the hain link problem. Display the on guration of the
hain on the s reen after ea h iteration of NRM.
3. Implement the idea of nding an using whi h we ensure that the error de reases
in every iteration. For the hain link problem, you will see that this gives smoother
movement towards the nal solution.
4. Something on hemi al equations?
Appendix A

Installing Simple pp

It should be possible to install simple pp on any system whi h has X Windows (X11) in-
stalled. We have installed simple pp on Ubuntu, Ma OS X, and Mi rosoft Windows running
Cygwin/X. To install, download
www. se.iitb.a .in/~ranade/simple pp.tar
untar it, and follow the instru tions in simple pp/README.txt.
You will need to have the GNU C++ ompiler, whi h is present on all the systems
mentioned above.

460
Appendix B

Managing Heap Memory

In Se tion 19.1 we dis ussed heap memory. We mentioned that managing heap memory is
tri ky. The simplest way to use heap memory is to use STL lasses su h as ve tors, maps,
queues, strings. These obje ts hide the memory management from the user, and provide a
onvenient interfa e whi h is generally adequate.
However, if you need to manage the memory yourself, you need to gure out what kind
of sharing you want to allow. In Se tion ?? we gave a solution in whi h we ensured that ea h
allo ated obje t is pointed to by exa tly one pointer. As a result, we an tell fairly easily
when the allo ated obje t is no longer needed and an be returned to the heap (Se tion ??).
This is in fa t the memory management idea used in STL, but it exe utes behind the s enes.
However, the onstraint that ea h obje t be pointed to by at most one pointer is not
always eÆ ient or onvenient. Say we have a large tree T. Let L be a subtree in it. Suppose
that we wish to onstru t another tree D whi h also ontains L. Then it is natural to share
the subtree: we should make the appropriate pointer in D point to L rather than needing to
make another opy of L to use as part of D. This will require less memory, and potentially
save the time required to opy. A similar example a tually arises in a program for omputing
the symboli derivative of an expression. Consider the rule for di erentiating produ ts:
d(uv )
dx
= v du + u dv
dx dx
When we represent symboli expressions as trees (Se tions 22.1.3 and 24.1), the produ e uv
will be represented by a tree with u; v being the left and right subtrees, and learly, u; v will
appear as subtrees in the formula for the derivative, spe i ally the left subtree of the right
subtree and the left subtree of the left subtree, see Figure B.1, (a) and (b). So it would be
natural to ask: an these two trees, the tree for the original expression and the tree for the
derivative, share subtrees, as shown in Figure B.1( )?
The diÆ ulty in sharing resour es is that it is harder to tell when a resour e is not needed.
If we de ide we dont need the tree denoting the original expression any longer, we annot
free the memory used by it, be ause that memory might be holding parts of the derivative,
whi h we might still need. One way to solve this problem is to use referen e ounting

461
Abhiram Ranade, 2013. Do not distribute 462

*
* *

u v
v du/dx u dv/dx

(a) u*v (b) d(u*v)/dx

+
T D

*
* *

u v
du/dx dv/dx

(c) Desired sharing of subtrees

Figure B.1: A fun tion and its derivative


Abhiram Ranade, 2013. Do not distribute 463
B.1 Referen e Counting
The basi idea is to asso iate a referen e ount with ea h obje t, in this ase ea h node of
the tree. The referen e ount of an obje t is simply the number of pointers pointing to that
obje t, indi ating how useful that obje t is. Ensuring that the referen e ount is orre tly
maintained is tri ky, but we rst des ribe what we would like to happen abstra tly. If we
add a new pointer to point to an obje t, we want one to be added to its referen e ount. If
we remove a pointer, then we want one subtra ted. When the ount of an obje t X drops to
zero, we de ide that X is no longer useful, and so we return the memory of X to the heap.
Note that X might itself be pointing to an obje t Y. In this ase we know that the pointer
to Y out of X will no longer be of use. So the referen e ount of Y should get de remented.
If the referen e ount of Y thus drops to zero, we an return Y also ba k to the heap, and so
on.
Coming ba k to our derivative example, suppose initially we only have the produ t tree.
Suppose the tree is pointed to by a variable T. Then every node, in luding the root is pointed
to by 1 pointer. Hen e at this point we want the referen e ounts of all nodes to be 1. Note
that we do not asso iate referen e ounts with variables su h as T if they are in an a tivation
re ord rather than in the heap. For simpli ity we will assume that T is indeed in the a tivation
re ord.
Suppose next we reate the derivative. Say the nodes of the derivative tree are all on
the heap, but its root is pointed to by a variable D in the a tivation re ord. Suppose we
did reate the derivative tree su h that it shares nodes with the original produ t tree, as
in Figure B.1( ). In this pi ture, the roots of the subtrees u; v have 2 pointers oming in.
Hen e after reation we would like the roots of these two nodes to have referen e ounts of
2 ea h.
Now suppose we write T=NULL. This would make the root of the original expression lose
the only pointer it had. So we would de rement the referen e ount of the root. We would
nd that the root of the original expression has referen e ount 0. So we an release the
memory of the root ba k to the heap. This would ause the pointers out of the root (of
the original expression) to be ome useless. Thus we would like the referen e ounts of the
obje ts they point to to be de remented. Thus at this point the referen e ounts of the
trees of u; v would both be ome 1. If after this we set D=NULL then if our referen e ounting
me hanism is working all referen e ounts will be ome 0 and everything would be returned
to the heap.
It is not too diÆ ult to implement referen e ounting manually. To ea h node we add a
referen e ount data member, and we have listed out the onditions under whi h this must
be in remented or de remented. However, the ode is umbersome, and unless it is designed
well, its use will also be umbersome.

B.2 The template lass shared ptr


This lass provides a standard solution for referen e ounting. This lass and the lass
weak ptr are known as smart pointers and are available in the Boost Smart Ptr library
available from www.boost.org. These pointers are also a part of C++11, and an be a essed
through the GNU C++ ompiler g++ by supplying the option -std=gnu++0x. Sin e our
Abhiram Ranade, 2013. Do not distribute 464
ompiler ommand s++ really alls g++, the option an also be supplied to s++ to get the
fun tionality. In addition, in your programs you need to in lude the header le <memory>.
A shared ptr is really a small stru ture that ontains the real pointer, and of ourse other
data needed to manipulate referen e ounts. The dereferen ing and assignment (and other)
operators are overloaded for shared ptrs so that they refer to the real pointer ontained
inside and also do the bookkeeping needed for referen e ounting. Thus in many ways a
shared ptr is like an ordinary pointer, and an be used almost as onveniently.
Ea h shared pointer has a member fun tion use ount whi h returns the referen e ount
of what the shared pointer points to. Note that in the ontext of shared pointers, we de ne
the referen e ount of an obje t to be the number of shared pointers pointing to it. You
need not on ern yourself with exa tly where the referen e ount is stored; just rely on the
guarantee provided to you.
B.2.1 Syntheti example
Figure B.2(a) shows an example of use of shared pointers, and the output produ ed when
the program is run.
The rst group of statements reates and initializes two shared pointers s1, s2 to two
instan es of A allo ated on the heap. When ea h instan e is reated, the onstru tor of
A prints the address of the instan e. In our exe ution these happened to be respe tively
0x804 008 and 0x804 030. Ea h obje t A ontains a shared ptr to another A obje t. The
last statement of the group sets s1->aptr to s2. This has the e e t that now s1->aptr
points to whatever s2 was pointing. After this we print the referen e ounts. As you an
see s1 points to 0x804 008, and nothing else points to it. However, s2 as well as s1->aptr
point to the same instan e 0x804 030. Thus the referen e ount of s1 is 1, and those of the
other two are both 2.
In the se ond group of statements we set s2 to point to a new instan e on the heap.
The reation auses its address 0x804 058 to be printed. Note that s2 was earlier pointing
to 0x804 030, so we should expe t its referen e ount to drop by 1. This indeed happens.
Now the three pointers s1, s2, s1->aptr are pointing to unique obje ts, and the referen e
ounts 1 1 1 are printed for them.
In the third group we set s1=NULL. Sin e s1 was earlier pointing to 0x804 008, its
referen e ount whi h was 1 should drop to 0. This should ause this obje t to be deleted
and returned to the heap. This indeed happens, the destru tor prints a message saying this.
Note further that when 0x804 008 is returned, the ontained pointer s1->aptr is no longer
valid. Thus the referen e ount of the obje t 0x804 030 pointed to by it should also be ome
0, and that should get destroyed. This also happens, as shown by the statement printed by
the destru tor. At the end of this group we print the referen e ounts of s1 and s2 only,
sin e s1->aptr is now invalid. These indeed ome out as 0 1, whi h is orre t be ause s1 is
NULL and s2 indeed points to 0x804 008, and is the only one to point to it.
The last print statement indi ates that 0x804 008 also gets deleted. This happens be-
ause when the program exits the s ope, delete ommands are issued on all lo al variables
of the urrent a tivation frame. Thus a delete ommand is issued on s1, s2. Provided a
shared pointer is non NULL, a delete on a shared pointer auses the referen e ount of the
pointed obje t to de rement, and if it de rements to 0 to delete that obje t as well. This is
Abhiram Ranade, 2013. Do not distribute 465
exa tly what happens!
B.2.2 General strategy
The pre eding dis ussion might suggest the following strategy for managing memory using
shared ptr:
1. First write the program without worrying about memory management, i.e. use ordi-
nary pointers and allo ate memory but do not worry about returning it.
2. Repla e every pointer whi h an potentially point to heap allo ated memory with a
shared ptr.
3. Initialize/assign to shared ptr only by a new obje t, or by the value of another
shared ptr or by NULL. Note that as in the pre eding program, you annot write
shared ptr<A> s1 = new A;, but you must expli itly onvert the pointer to a shared ptr.
This strategy works well sometimes. For example, it works quite well for the derivative
nding program. We dis uss this in Se tion B.2.3.
This strategy may not work, for several reasons. One possibility is that you may have
pointers for whi h rule 3 above annot be applied, be ause originally they were being used
to hold new addresses as well as addresses of variables in a tivation frames. In this ase you
will need to reorganize your program.
However, any implementation of referen e ounting (in luding that provided by shared ptr)
has one fundamental limitation: if your pointers form y les, then you will have memory
leaks even with shared ptrs. We will see this in Se tion B.2.4.
B.2.3 Shared pointer in derivative nding
We rst develop the ode whi h does not worry about returning dynami memory. For
this we use the representation for trees developed in Se tion 22.1.3. The ode is shown in
Figure B.3.
First we have a onstru tor for onstru ting terminal or literal nodes. Then we have the
onstru tor for non-leaf nodes. These follow along the lines of Se tion 22.1.3. Next we have
fun tions Sum, Prod and Lit that in lude the new operator and thus reate the node on the
heap. These are onvenient to use and the main program at the end uses them. Then we
have a str fun tion whi h onverts the expression represented by the subtree underneath
the node into a string.
Finally, we have the deriv fun tion. This uses the de nition: the derivative of a sum
is the sum of the derivatives, the derivative of a produ t is as per the rule dis ussed above,
and the derivative of a literal is 1 if and only if the literal is x.
To this ode we an apply our re ipe for adding in shared ptrs. We only have one kind
of pointer in this ode: Exp*. And as you an see, it is always used to point to heap allo ated
obje ts. Also, the pointer stru tures reated in this program will not have y les. So we do
the following:
1. Repla e every Exp* with shared ptr<Exp>. For this it is better to de ne typedef
shared ptr<Exp> spE;, and then repla e Exp* by spE.
Abhiram Ranade, 2013. Do not distribute 466

#in lude <simple pp>


#in lude <memory>

stru t A{
shared_ptr<A> aptr;
A(){ out << "Creating A: "<< this << endl;}
~A(){ out << "Deleting A: "<< this << endl;}
};

int main(){
shared_ptr<A> s1(new A), s2(new A); // Group 1
s1->aptr = s2;
out << s1.use_ ount() << " " << s2.use_ ount() << " "
<< s1->aptr.use_ ount() << endl << endl;

s2 = shared_ptr<A>(new A); // Group 2


out << s1.use_ ount() << " " << s2.use_ ount() << " "
<< s1->aptr.use_ ount() << endl << endl;

s1 = NULL; // Group 3
out << s1.use_ ount() << " " << s2.use_ ount() << endl << endl;
}

---------------------- Output produ ed --------------------------

Creating A: 0x804 008


Creating A: 0x804 030
1 2 2

Creating A: 0x804 058


1 1 1

Deleting A: 0x804 008


Deleting A: 0x804 030
0 1

Deleting A: 0x804 058

Figure B.2: Program to test shared pointers and its output


Abhiram Ranade, 2013. Do not distribute 467

#in lude <simple pp>

stru t Exp{
Exp* lhs;
Exp* rhs;
har op;
string value;
Exp(string v) : value(v) {lhs=rhs=NULL; op='A';}
Exp( har o, Exp* l, Exp* r) : lhs(l), rhs(r), op(o) { value="";}
stati Exp* Sum(Exp* l, Exp* r){ return new Exp('+', l, r);}
stati Exp* Prod(Exp* l, Exp* r){ return new Exp('*', l, r);}
stati Exp* Lit(string v){return new Exp(v);}
string str(){
if (op == 'A') return value;
else return "(" + lhs->str() + op + rhs->str() + ")";
}
Exp* deriv(){
if(op == '+') return Sum(lhs->deriv(), rhs->deriv());
else if(op == '*') return Sum(Prod(lhs->deriv(), rhs),
Prod(rhs->deriv(), lhs));
else return Lit(value == "x" ? "1" : "0");
}
};

int main(){
Exp* e = Exp::Sum(Exp::Lit("x"), Exp::Prod(Exp::Lit("x"), Exp::Lit("x")));
out << e->str() << endl;
Exp* f = e->deriv();
out << f->str() << endl;
}

Figure B.3: Mini symboli di erentiation program


Abhiram Ranade, 2013. Do not distribute 468
2. Che k assignments to Exp* variables. If other Exp* variables were being assigned, then
therefore there should be no problem be ause both are onverted to spE. However, there
an be new expressions that were assigned to Exp* variables. These now have to be
expli itly onverted to spE type. So you will have to do this.
With these two steps, your program should work. Add ode to the onstru tors to observe
when they are alled, and add destru tors so that you know when they are alled as well.
You should observe that while taking the derivative of a produ t uv the expressions for u
and v are not opied. So they must be shared. You an also see that the nodes are destroyed
when the program terminates. So there is no memory leak either.
B.2.4 Weak pointers
Consider a program fragment that uses the stru t A from Figure B.2:
int main(){
shared_ptr<A> s1(new A), s2(new A);
s1->aptr = s2;
s2->aptr = s1;
s1 = NULL;
s2 = NULL;
}

At this point s1 If you exe ute this, you will merely get:
Creating A: 0x804 008
Creating A: 0x804 030

Even when the program nishes, you will not get any deallo ations to happen, as you did
in the last line of the output of Figure B.2. Let us tra e the exe ution to see why. Clearly,
the reation of s1,s2 aused the messages about reating A to be printed. After that, the
instru tion s1->aptr = s2; s2->aptr = s1; auses s1,s2->aptr to point to 0x804 008,
and s2,s1->aptr to point to 0x804 030. Thus the referen e ounts of all 4 shared pointers
are 2. Now onsider what happens when we set s1 = NULL; { one referen e to 0x804 008
goes away. But it still has 1 referen e, and hen e no delete happens. When we set s2 =
NULL; next, { one referen e to 0x804 030 goes away. But this also has one referen e. Thus
even after we set s1, s2 to NULL, the obje ts at 0x804 008 and 0x804 030 ontinue to have
referen e ount 1, the pointer inside the rst ontributes the ount to the other and vi e
versa. But our program annot a ess these obje ts, and they havent been returned to a
heap: so we have a memory leak.
B.2.5 Solution idea
This problem an only be solved using so alled the lass weak ptr in onjun tion with
shared ptr.
The basi idea is to break every pointer y le by putting one weak ptr in it. A weak ptr
is a pointer whi h does not in rement the referen e ount. However, if the obje t pointed to
Abhiram Ranade, 2013. Do not distribute 469
by the weak pointer is deleted, then the weak pointer be omes NULL. So whenever you wish
to traverse a weak pointer W, you an rst he k if *W is not NULL and only then traverse.
If you are working in a setting in whi h there are multiple threads, then you might need to
lo k the pointer rst.

B.3 Con luding remarks


Managing heap memory in C++ is an evolving eld. As a novi e programmer, your needs
will probably be met by the lasses in STL. If for some reason you need to go beyond that,
ideas su h as shared ptr (and also weak ptr if ne essary) will likely be adequate. There is
work on so alled garbage olle tion strategies, but that is beyond the s ope of this book.
Appendix C

Libraries

The term library is used to refer to a single le whi h olle ts together several obje t modules.
Suppose you have onstru ted obje t modules g d.o, l m.o. Then you an put them into
a single library le. On unix, this an be done using the program ar, and it is ustomary use
the suÆx .a for library (ar hive) les, and so you might hoose to all your library g dl m.a.
This an be done by exe uting
ar r s g dl m.a g d.o l m.o
Here the string r s indi ates some options that need to be spe i ed, whi h we will not
dis uss here. This ommand will ause g dl m.a to be reated.
When ompiling, you an mention the library le on the ommand line, pre xing it with
a -L; modules from it will get linked as needed. In fa t you ould send the le to your friends
who wish to use your g d and l m fun tions, along with an header le, say g dl m.h, whi h
ontains the de larations of g d and l m (but not the de nitions). This is the preferred
me hanism for sharing ode. Note that your friends will not be able to easily know how your
fun tions work, be ause you need not send them the orresponding . pp les.
C.0.1 Linking built-in fun tions
You an now guess how built-in fun tions su h as sqrt or are linked to your program. They
are in libraries, whi h s++ supplies when needed! Commands su h as sqrt are ontained
in the math library that is supplied as a part of C++. Our ompiler s++ automati ally
in ludes the orresponding library while it ompiles your programs. Of ourse, this is not the
entire story { you need to have the prototype for sqrt and other fun tions at the beginning
of your program.
These prototypes are present in a le alled math.h, whi h you an insert into your
program by putting the following line at the beginning of your program:
#in lude < math>
Our ompiler knows where to nd this le and pla es it in your program.
But did you remember to in lude this le? You might remember that you did put in a
similar line in your le:
#in lude <graphi sim.h>

470
Abhiram Ranade, 2013. Do not distribute 471
Be ause of this the le graphi sim.h is pi ked up from some pla e known to s++ and is
pla ed in your le in pla e of this line. This le ontains the line #in lude < math.h>
whi h auses the le math.h to be in luded!
Appendix D

Reserved words in C++

The following words annot be used as identi ers.

472
Appendix E

Operators and operator overloading

We will dis uss some of the less frequently used operators, and then onsider operator over-
loading.

E.1 Bitwise Logi al operators


C++ allows bitwise logi al operations to be performed on variables of integer types. For
simpli ity we will only onsider operations on the unsigned types.
E.1.1 Or
The operator | is the bitwise OR operator, i.e. p | q returns a number that is obtained by
taking the binary representations of p,q, and omputing the OR of the orresponding bits.
Note that the logi al OR of two bits is a 1 if and only if at least one of the bits is 1. Here is
an example.
unsigned int p=10, q=6, r;
r = p | q;
This would ause the bit pattern
00000000000000000000000000001010
for 10 (de imal) to be OR'ed with the bit pattern
00000000000000000000000000000110
for 6, to get the result
00000000000000000000000000001110
whi h is the bit pattern for 14. Thus at the end r would be 14.

473
Abhiram Ranade, 2013. Do not distribute 474
E.1.2 And
The operator & performs bitwise logi al AND. Note that the logi al AND of two bits is 1 i
both bits are 1. Thus for p,q as de ned above, if we write:
unsigned int s = p & q;

s would get the bit pattern 0000000000000000000000000000010, whi h is the bit pattern for
2. Thus at the end s would equal 2.
E.1.3 Ex lusive or
The operator ^ is the bitwise ex lusive OR operator. Note that the logi al ex lusive OR of
two bits is 1 if and only if exa tly one of the bits is 1. Thus if we write
unsigned int t = p ^ q;
the variable t would get the bit pattern 0000000000000000000000000001100, whi h is the
bit pattern for 12. Thus t would be 12 after the statement.
E.1.4 Complement
Finally the operator ~ is the (unary) bitwise omplement operator. The omplement of a bit
is 1 if and only if the bit is 0. Thus if we write
unsigned int u = ~p;
the bit pattern for u would have 0s wherever p had 1s and vi e versa. Thus we would have
1s in all positions ex ept
P thei positions of pla e value 2 and 8. Thus the value of u after the
statement would be ( i 2 ) 2 8 = 4294967285.
31
=0

E.1.5 Left shift


The operator << is used to shift a bit pattern to the left. Thus x << y would ause the bit
pattern for x to be shifted left by the the value of y. By this we mean the following operation.
We rst throw away the most signi ant y bits, and then append y zeros on the right. The
resulting bit pattern is the result of the operation. Note that if the most signi ant x are
zero, then x << y is simply x2y , where x; y are the values of x and y respe tively.
For p, q as we de ned, i.e. having values respe tively 10 and 6, if we write
unsigned int v = p << q;
the variable v would get the bit pattern 0000000000000000000001010000000. This has the
numeri al value 10  2 = 640.
6
Abhiram Ranade, 2013. Do not distribute 475
E.1.6 Right shift
The operator >> is used to shift a bit pattern to the right. Thus x >> y would ause the
bit pattern for x to be shifted right by the the value of y. By this we mean the following
operation. We rst throw away the least signi ant y bits, and then append y zeros on the
left. The resulting bit pattern is the result of the operation. Note that x >> y is simply
x=2y (integer division), where x; y are the values of x and y respe tively.
For v as we de ned above, i.e. having value respe tively 640, if we write
unsigned int w = v >> 2;
the variable w would get the bit pattern 0000000000000000000000010100000. This has the
numeri al value 160.

E.2 Comma operator


A omma expression has the form
lhs, rhs
where lhs and rhs are expressions. The operator auses the evaluation of both the expres-
sions, and the value of rhs is used as the result of the omma expression.
The omma operator an be used to for e the evaluation of multiple expressions in settings
where synta ti ally only one expression is expe ted.
A ommon use is to have multiple in rement and de rement operations in a for statement.
for (int y = 10, x=0; y>0; y--, x++)
out << x << endl;
This would print the numbers 0 through 9.
As another example, using the omma operator, our mark averaging program of Se -
tion 7.1.2 an be written more ompa tly as follows.
main_program{
float nextmark, sum=0;
int ount=0;

while( in >> nextmark, nextmark >= 0){


sum = sum + nextmark;
ount = ount + 1;
}

out << "The average is: " << sum/ ount << endl;
}
However, usage su h as above is not ommon, and hen e is not re ommended.
Also note that the omma operator should not be onfused with the use of the omma
as a delimiter in de larations e.g. oat nextmark, sum=0; above, or fun tion alls, e.g.
f(a,b).
Abhiram Ranade, 2013. Do not distribute 476
E.3 Operator overloading
We have dis ussed the basi ideas of operator overloading in Se tion 16.4 and Se tion 16.5.
Here we dis uss some details.
The following pre x unary operators an be overloaded
+ - * & ! ~ ++ --
For any operator  in the list above, overloading an be done either by de ning a member
fun tion operator in the lass of the operand taking no argument, or by de ning a fun tion
operator taking a single argument of the type of the operand.
The unary suÆx operators ++, -- an also be overloaded. You again de ne a member or
ordinary fun tion operator like the pre x versions. However to distinguish from the pre x
versions, you also have an extra int argument whi h you ignore. This might seem arbitrary,
and it ould indeed be onsidered a ha k.
Appendix F

The stringstream lass

The lass iostream is used to de ne obje ts su h as in and out on whi h we an use the
extra tion operators >> and << respe tively to read or write data. The obje ts are alled
streams, be ause data ows in and out of them.
A stringstream is a stream obje t, but it is onstru ted out of a string. To use it, you
need to in lude the header <sstream>. This is espe ially useful in extra ting numbers from
strings or onverting numbers to strings.
As an example, here is a program that takes two double numbers as ommand line
arguments and prints their produ t.
#in lude <sstream>
int main(int arg , har *argv[℄){
double x,y;
stringstream(argv[1℄) >> x;
stringstream(argv[2℄) >> y;
out << x*y << endl;
}
In this we have used the stringstream fun tionality provided in C++, by in luding <sstream>.
The fun tion stringstream takes a single argument s whi h is a hara ter string, and on-
verts it to an input stream (su h as in). Now we an use the >> operator to extra t elements.
Thus stringstream(argv[1℄) >> x; would extra t a double value from the se ond word
typed on the ommand line. Similarly a double value would be extra ted into y from the
third word. Thus if you typed
a.out 4 5e3
The answer, 20000 would indeed be printed.
Here is another example.

int main(int arg , har *argv[℄){


string s="1 2 3";
int x,y,z;
stringstream(s) >> x >> y >> z;

477
Abhiram Ranade, 2013. Do not distribute 478
stringstream t;
t << x*y <<' '<< y*z;
out << t.str() << endl;
}
As you an see, in this we have made multiple extra tions from the same stringstream. This
is allowed. Basi ally everything that you an do with streams is allowed on stringstreams.
The stringstream t is used for output, and we have put multiple values into it. Finally, the
member fun tion str allows us to extra t the string out of a stringstream, whi h an be
printed out if desired.
Appendix G

The C++ Prepro essor

479
Appendix H

Lambda expressions

A lambda expression is a nameless fun tion whi h an be onstru ted pretty mu h anywhere
in your ode and subsequently used. The following expression, for example, represents a
fun tion whi h ompares integers by their absolute values:
[℄(int a, int b){return abs(a) < abs(b)}
You an use this dire tly, by supplying arguments:
[℄(int a, int b){return abs(a) < abs(b)}(3,-5)
whi h will evaluate to true, sin e j3j < j 5j. But more usefully, su h an expression an be
used wherever a fun tion is needed, e.g. as the omparison fun tion for sorting. Thus the
following ode fragment is legal.
#in lude <algorithm> // so that sort an be used
int a[100℄;
... ode to initialize a...
sort(a,a+100, [℄(int a, int b){return abs(a) < abs(b)});

This will indeed sort the array a in non-de reasing order of the absolute values. As you
an see, this is more ompa t than de ning a named fun tion, or de ning a lass and over-
loading the fun tion all operator (Se tions 20.4.2,20.4.3). For example, the all to sort in
Se tion 20.4.3 ould have been written as
sort(sve .begin(), sve .end(), [℄( onst student& a, onst student& b){
return a.rollno < b.rollno;});
without having to de ne the ompareRollnoStru t as was done there.
The C++ standard adopted in 2011 supports lambda expressions. These have many
uses, e.g. see Chapter 25 and Chapter 26. Lambda expressions were originally proposed in
languages su h as LISP.

480
Abhiram Ranade, 2013. Do not distribute 481
H.1 General form
Lambda expressions an be spe i ed in many ways. We rst dis uss the form used above.
[℄(parameter-list){body}
In this, parameter-list gives the list of parameters that the fun tion needs, and the body
give the ode that is to be exe uted. You have already seen examples of this above.
Note that we have not expli itly stated the return type of the fun tion. C++ will infer
this on the basis of the return statements in body. Sometimes, C++ may not be able to
infer orre tly, in whi h ase you an spe ify the return type as follows.
[℄(parameter-list) -> return-type {body}
Thus you ould write
[℄() -> int {return 1;}
Sin e 1 an have many types, the above lari es that we mean a fun tion whi h returns an
int.

H.1.1 The type of a lambda expression


A lambda expression an be onsidered to have the type
std::fun tion<return-type(parameter-types)>
where return-type is the return type of the lambda expression and parameter-types are
the types of the parameters ( omma separated). To use this you must in lude the header
le <fun tional>.
For a use of this see Se tion 25.1.3.
H.1.2 Variable apture
The body of a lambda expression may a ess names whi h are de ned outside the lambda
expression, but are visible in the s ope in whi h the lambda expression is de ned. Su h names
are sometimes alled free names of the lambda expression (as opposed to those variable names
that are de ned or bound inside the lambda expression). The free names an either denote
the values of the orresponding variables at the time the lambda expression was de ned, or
denote the referen es to the orresponding variables. The former is alled \ apture of free
names by value" and the latter \ apture of free names by referen e". To denote apture by
value, we simply give the names in the initial [℄, to denote apture by referen e, we give the
names pre xed by &. Here is an example.
int main(){
int m=10;
std::fun tion<void()> f = [m℄(){ out << m << endl;};
std::fun tion<void()> g = [&m℄(){ out << m << endl;};
Abhiram Ranade, 2013. Do not distribute 482

m++;

f();
g();
}
In this f,g apture m by value and by referen e respe tively. Thus the all f() will print
10, whi h is the value of m at the time f got de ned. The all g() on the other hand will
print 11, whi h is the urrent value of m sin e g has aptured m by referen e.
If you wish to apture a by referen e and b by value, you may spe ify the apture as
[&a,b℄. If you want all to be aptured by value (referen e) you may spe ify the apture as
[=℄ ([&℄). If you want all to be aptured by value ex ept for a,b, you may write [=,&a,&b℄,
and analogously.
Note that writing the apture as [℄ spe i es no apture.
For more examples of variable apture see Chapter 25.
H.1.3 Dangling referen es
If you apture a variable by referen e, and the variable is deallo ated between the apture
and the use, then we have the problem of a dangling referen e. Thus apture by referen e
must be done arefully.
H.1.4 Capturing this
The this pointer, i.e. the pointer to the obje t whose member fun tion is being exe uted
should be aptured by value, after all, what we need is the ontent of the pointer. Further-
more, on e you apture this, you an refer to members of the obje t by giving the names
dire tly, without pre xing them with this->.

You might also like