Professional Documents
Culture Documents
Introduction To Programming in C++ by Abhiram Ranade
Introduction To Programming in C++ by Abhiram Ranade
Do not distribute
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 Identiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 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 Innity 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 denitions . . . . . . . . . . . . . . . . . . . . . . . . . . 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 dierent 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 dened 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 Dening 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 Denition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 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 Dening 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 dened 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 Surng 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
oee 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 dierent from merely learning the dierent 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 benet 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.
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.
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 magnied 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 dierent 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
dierent programs the same
omputer
an be made to behave in dramati
ally dierent 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.
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
ied 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 dene the variable nsides. As many
variables as you want
an be dened, either by giving separate denition statements, or by
writing out the names with
ommas in between. For example, int nsides, length; would
dene 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
ied 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 dierent 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
ied. 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
ied. 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.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);
}
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 dierent
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.
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
onden
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
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 dierential 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.
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
in
lusive.
A more
ommonly used representation is the so
alled 2's
omplement representation. The
n bit 2s
omplement representation is dened 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
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
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.
apable of storing 1 bit. The number of bits that
an be stored is dened 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
Control Unit
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
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 dierent 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.
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 dierent examples.
3. How many dierent 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 dierent 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.
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
3:4028 1038
10 , as 6.022E23. The signi
and as well as the exponent
ould be spe
ied with a minus
23
sign, if needed, of ourse. For example the mass of an ele tron, 9:10938188 10 kg, would 31
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;
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.
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 ae
ts less signi
ant
bits, then the operation will have no ee
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 ee
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 dierent 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 dierent 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 dier 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 dierent 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 dierently for
dierent 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 Innity 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 innity for all subsequent
omputation. By this, we mean that anything
added to innity remains innity, 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 undened 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 innities 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;
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 dierent 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 ee
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;
float num,sum=0;
repeat(
ount){
out << "Give the next number: ";
in >> num;
sum = sum + num;
}
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 dened 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;
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 dier, 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 dened 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.
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 denitions
It turns out that most C++ programmers would write the average
omputation program
from Se
tion 3.4 slightly dierently, 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;
}
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;
out << x << " " << y << " " << z << endl;
out << u << " " << v << " " << w << 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 dierent 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 modied 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 dierently, state the inputs for whi
h the programs
will behave dierently.
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
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 innite 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.
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.
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.
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
onrm 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 dierent 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.
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
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
ied by giving the
oordinates on the s
reen,
rather than always having to be spe
ied 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 dierent 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.
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);
}
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().
By the way, 65536 = 2 ; so when you
ompute v = 65536 x + y, you are ee
tively pla
ing
16
the x oordinate in the most signi ant 16 bits of v and y in the least signi ant 16.
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);
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
denition of \
losest".
A natural denition 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
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
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.
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. Modify the proje
tile motion program to tra
e the traje
tories of the proje
tile for the
same initial velo
ity and dierent 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 ee
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 diused. This is the so
alled
spheri
al aberration in a
ir
ular mirror.
Chapter 6
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 simplied 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.
91
Abhiram Ranade, 2013. Do not distribute 92
Previous Statement
True
Condition
Consequent
False
Next 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;
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 dierent, see Appendix E.
Abhiram Ranade, 2013. Do not distribute 94
Read income
True
income <= 180000
Tax = 0;
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;
False True
Condition
Alternate Consequent
Next Statement
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;
False True
Condition 1
Consequent 1
False True
Condition 2
Consequent 2
False True
Condition3
Alternate Consequent 3
Next Statement
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 simplies 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
print tax
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();
repeat(100){
int
li
kPos = getCli
k();
int
x =
li
kPos/65536;
int
y =
li
kPos % 65536;
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;
}
}
}
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.
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 denition. 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;
}
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
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
110
Abhiram Ranade, 2013. Do not distribute 111
Previous statement in the program
False
Condition
True
Body
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
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 dieren
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;
(a) (b)
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.
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 innitum. 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.
do{
out << ``Type the number whose square root you want: ``;
in >> x;
out << ``The square root is: `` << sqrt(x) << endl;
Initialization
False
Condition
True
Body
Update
In this
ase, we will have shadowing, as dis
ussed in Se
tion 3.6.3. In parti
ular the i dened
in the rst statement will be dierent from the one dened 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 dened 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;
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;
while(m % n != 0){
int Remainder = m % n;
m = n;
n = Remainder;
}
out << "The GCD is: " << n << endl;
}
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 dene 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 qualies 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
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.
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;
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
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
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
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.
x 2 = 0, i.e. x = 2 and this would give us the square root of 2. So nding roots is a
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 dierent 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 dierent 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
the right hand side of this equation
an be evaluated. Thus we
an get an approximation to
( )
B (xi ; f (xi))
Root C A
xi+1 xi
f (x)
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 undened.
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
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
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.
Sin
e we dont already have su
h a g
d fun
tion, we must dene 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
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.
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 dened 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.
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.
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. ee
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 denition 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
denition 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 denes 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
ied 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 dene 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 ee
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 dierent 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.
Let us rst make sure that the types of the arguments in the
all and the parameters in
the fun
tion denition 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 denitely
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.
Given this denition, 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 prex 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.
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 dened 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
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
(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 dierentiation: 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 dierentiating the sum u + v is the
same as that of rst dierentiating 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 dierentiating u or of dierentiating v are indeed simpler than the
problem of dierentiating 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 indenitely. The problems whi
h we expe
t to solve dire
tly are
alled the base
ases. Considering dierentiation 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.
Height h tree
// 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);
}
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 dene 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 denite 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
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
V1 = 1 V2 = 2 V3 = 3 V4
se
ond last last
urrent
(a)
V1 = 1 V2 = 2 V3 = 3 V4 = 5 V5
(b)
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.
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 dened 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 dened re
ursively as n
r
= n1
r
+ n
r
, for 1
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 dened 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 dened 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 dened 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
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 dierent
fun
tions needed for a program are in dierent 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 dierent programmers might use the same name to
dene 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. Ee
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.
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 dierently. 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 dened so far, it will be dened 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 denition 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 identier
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.
(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 dierent programmers are working on dierent 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 dened either in the same
module or in one of the other modules being linked. After this
he
k, the
ode in the dierent
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
denition of header les, whatever is in d.h will get in
luded, and hen
e dened 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 dened. Only if it is not dened, then the rest le, till the line #endif is pro
essed.
Noti
e that the se
ond line, should it be pro
essed, will dene GCDLCM H. This will ensure
that subsequent in
lusions of the le g
dl
m.h will have no ee
t.
Note that prepro
essor variables, unlike C++ variables,
an be dened 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 dened 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.3 Namespa
es
We next
onsider an important question whi
h typi
ally arises when a program makes use of
fun
tions developed by dierent people, developed possibly at dierent times. The question
is: what happens if you borrow
ode from two programmers, both of whom have dened 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 dene 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 dierent fun
tion names or dierent 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 Denition
You
an dene 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 dene 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 denition (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 denition 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 denition of mySpa
e above, you
may dene 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 denition uses the name g
d without prexing
it with the name of the namespa
e. This is ne; the denition 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 denition and the denition 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 dened 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
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 dene 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
qualier, 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 dened above, and further we have put a
using namespa
e mySpa
e; dire
tive in our main program.
using namespa
e mySpa
e;
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 denitions had a dierent 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 dene 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 dene 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 denitions are made inside header les, and in su
h denitions only
de
larations are put. The fun
tion denitions are put in implementation les, in whi
h the
header le
ontaining the namespa
e denition 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 denition, 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.
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);
}
(
) 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 dened 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
dened 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 dene spa
e for i, it merely de
lares i to be an int whi
h will be
dened 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 denition prexed 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
denition of the variable.
We nally note that individual fun
tions may
ontain denitions 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).
int main(){
out << "Give area of square: ";
double area;
in >> area;
out << "Sidelength is: " << sqrt(area) << endl;
}
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 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.
int main(){
double y = bise
tion(1,2,0.0001,&f);
out << "Sqrt(2): " << y << "
he
k square: " << y*y << endl;
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 dierent. After you write a program, you
ompile and run the program and you
test it by providing dierent 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 oer suggestions with
a view to (a) in
rease the
onden
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
ertied 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
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 dened. 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.
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 eort, 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.
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 eort.
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
ondently 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 \
ondent 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 dene the prepro
essor (Appendix G)
variable NDEBUG. This will have the ee
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 dierent from what you expe
t. What do you do?
The most natural response is to try and nd out when the program starts behaving
dierently 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 dierent. 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 oer 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 dierent 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.
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 dierent 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.
while(n>0){
n = n/10;
++d;
}
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.
215
Abhiram Ranade, 2013. Do not distribute 216
This single statement denes 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 identier (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 dene arrays of other kinds also, e.g.
float b[500℄; // array of 500 float elements.
You
an mix up the denitions of ordinary variables and arrays, and also dene several arrays
in the same statement.
double
, x[10℄, y[20℄, z;
This statement denes 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 dene arrays in the main program or inside fun
tions as you wish. Note however,
that variables dened inside fun
tions are destroyed on
e the fun
tion returns. This applies
to arrays dened in fun
tions as well.
As per the C++ standard, the length of the array should be spe
ied in the denition
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℄
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 dene 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 dierent. 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;
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;
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 ee
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 dened 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
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
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.
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 ee
tively
2 2 2
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 dierently, 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.
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 denition 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 denition. 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
ied 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.
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
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 dened 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.
+
addp(a,b,
,5);
prodp(a,b,d,5);
The prex
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 dened 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 dene 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, dene 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.
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 dened 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 dened 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
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 dened just as you dene arrays of doubles or ints.
har name[20℄, residen
e[50℄;
The above denes 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 dene 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 dierent
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 dened, 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 prex of b. Be
ause prexes 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
satised. 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
}
}
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℄ dier 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 dened:
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 denition 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℄;
2x + 6x + 8x = 38
1 2 3
7x + 4x + 9x = 22
1 2 3
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℄;
Polygon penta(200,200,pentaV,5);
Polygon star(200,400,starV,5);
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.
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 dierently. 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.
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.
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
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.
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
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 dieren
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
ied 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 dene the arrays using n as dened above.
This way it should be possible to use your program to solve systems of dierent 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
denition 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 dened 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 dened 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
Write a program whi
h re
eives points p ; : : : ; pn on the graphi
s
anvas and plots the
1
Bezier
urve dened 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 dierent 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 dene 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 dierent 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 dierent 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.
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 dene 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 denition does not by itself
reate variables or reserve spa
e. But we
an use it to dene 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 ee
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 dened 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 dened
har array, so
an we into this member of pqr.
We
an initialize stru
tures in a manner similar to arrays. Assuming Book dened 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 dened above, we
an further write:
Abhiram Ranade, 2013. Do not distribute 267
Cir
le
2;
2 =
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;
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.
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 modied.
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 modied.
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 dened 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 modied.
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).
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
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.
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 dened 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 denitions 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 qualiers wherever possible. First, if any of the arguments
is not modied by the fun
tion, then the
orresponding parameter should also be de
lared
onst. Se
ond, if the re
eiver is not modied 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 modies 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.
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 prexing
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 denition of Point, the variable
ounter
an
be referred to by using the name
ounter, outside the denition a stati
variable must be
referred to by prexing 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 denition of the stru
ture
Point does not a
tually
reate the stati
data variables; a stru
t denition 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 denition of resetCounter to the denition 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 denition,
and by prexing the stru
ture name and :: outside the denition. 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 denition 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 denition 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.
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 modied, 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 dierent 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 dened 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.
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
ied 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
dierent for ea
h
onstru
tor.
Whenever a variable of stru
ture-type is dened 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 denition 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 denition 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 denition 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
dierent: 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 dierently.
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);
}
}
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.
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.
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.
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 dened,
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.
With this denition, 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
dened 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
denition, 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 dene 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 denition. Thus if we make the assignment
operator private, then ee
tively we are forbidding assignment for the stru
ture. If we make
the
opy
onstru
tor private, then we are ee
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 denition.
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 dene 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 dene 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 denition.
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 ee
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 denition of stru
ture
A. To do this you merely insert the line friend A; inside the denition of stru
ture B.
16.8 Classes
A stru
ture as we have dened it, ex
ept for a minor dieren
e, is more
ommonly known in
C++ as a
lass.
The small dieren
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
ier 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 denition.
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.
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
ied either as float or double. We have only shown 2 member fun
tions for brevity.
One is dened in-line, the other is dened outside the
lass denition. Note that you must
put the line template<T> before the member fun
tion dened outside as well.
Note that the template denition 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 dene 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.
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 myinle 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 eort. 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 eort in the long run.
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 dened 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. Dene 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
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 dierent
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 dierent
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.
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 ee
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 rened 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 rened methods. These are outside the s
ope of this book.
arstep(n,stars, delta);
3
3000
10
100 497.00436 375.691247 0 0.466203685 0.43236573 0
Abhiram Ranade, 2013. Do not distribute 309
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.
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
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 dierent, or polynomials, where the number of
oeÆ
ients
might be dierent. We may also be
alled upon to represent graphs (e.g. road networks) or
the set of sets of students in dierent
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 dierent 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
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 dened 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 deniteness 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 dierent. 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!
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 dening the
opy
onstru
tor yourself, you
an
ontrol how the three operations
above happen! If you do not dene 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 innite
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!
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
19.4 Remarks
We have shown how we
an dene a data type String to store
hara
ter strings. We showed
that the denition 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. Ee
tively, using our denition, 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 dened, 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℄;}
};
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. Dene 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. Dene the modulo operator % for polynomials. Suppose S (x); T (x) are polynomials,
then in the simplest denition, 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 dene the remainder S (x) mod T (x) to be
any kR(x) where k is any number, where R(x) is as dened 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;
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);
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 denition 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
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 eort.
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.
The rst statement will dene 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 dened to mean
on
atenation for strings. Thus given the
previous denitions 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 dened. 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
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 dened 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.
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 denition 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 dierent 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 modied.
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℄;
}
Se
tion 20.4.3.
Third, we
an dene 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);
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 dene 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 denition of operator< does, in the
ode below. Note an
important point: the sort fun
tion requires that the fun
tion operator< be dened, 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);
}
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 dierent. Ee
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 ee
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 ee
t you expe
t: the element
reated the rst time around will be
modied 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 dening 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 dened 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 dierent
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
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 dened as follows.
Abhiram Ranade, 2013. Do not distribute 346
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
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";
}
}
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.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.
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
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 prex 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
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 dene 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 dierent
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 dierent 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℄;
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 denition now be
omes:
stru
t Person{
string name;
ve
tor<Person*> friends, enemies;
Person* favourite;
}
Given our pre
eding denitions, 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 denition 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 denes 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;
}
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.
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 surng 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
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
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 dierent pages as the time
in
reases. Indeed, if you
ompute xT , we get
10
3 Ohm
2 Ohm
! Ampere
3 4
5 Ohm
6 Ohm
7 Ohm 8 Ohm
3 Ohm
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 dierent nodes, so we dene
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 dierent 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
ied 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 dierent 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 dened 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.
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
ied 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/
))
x+1 x
4. + +6
x+3 5
((((x+1)/(x+3))+(x/5))+6)
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
/
+
/
+ + 6
+ /
a
b c x 1 x 3 x 5
(a)
(b)
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
dene 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 identier 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:
+
There is a dieren
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
ied 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 dene 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 identier 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 dierent 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 dene 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-
tier 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.
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 dene 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 oset 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
ied 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.
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)
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 dene
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
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
ied as (L I U E).
9. As we have dened, 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
ied 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 dierentiation 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 simplied. 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 denition 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:
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);
}
}
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 redene 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 dier-
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 dened in the
lass
orresponding to the
ategory. These attributes will be
inherited when we dene sub
lasses
orresponding to the sub
ategories. In ea
h sub
lass we
need additionally dene the attributes whi
h are spe
i
to the
orresponding sub
ategory.
For example, in the
ir
le sub
lass we
ould dene 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.
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 dene 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 dened fun
tions su
h as right. We have not expli
itly dened
the member t of type Turtle. As we will see next, these are inherited!
distance : double
to override the old denition, and will be used for obje
ts of
lass B. The denition 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
denition 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 denition of mTurtleI in Se
tion 23.1.2. We
dened 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 redened 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 denition of B, as well as
outside the denition 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 denition of B. And of
ourse it
annot be a
essed outside. In other
words, private members are a
essible only inside the denition of the
lass in whi
h the
member was dened (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 denition 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 denition 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 denition 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
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 denition 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 denition of B. Further, the
publi
members init, and r
an be used if needed in both B as well as main.
On
e the oending 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 dened 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;
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 denition 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.
The member root will store the verb itself. We have dened 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";}
};
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 denitions
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 dene 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.
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.
P1 P2
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 benet 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.
Dene 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. Dene a
lass realTurtle su
h that realTurtle obje
ts move with some spe
iable
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
;
}
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 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 dened 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: dierent
programmers
an work on the dierent parts simultaneously. As we will see, inheritan
e
based designs have mu
h to oer 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 dene 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.
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 dened dierently depending upon the type
of the operator.
Here is the denition 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;}
};
int main(){
initCanvas("Formula drawing");
e.setSize();
e.draw(200,200+e.getHeight()-e.getDes
ent());
getCli
k();
}
Rectangle Turtle
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 dierent, 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 dened 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 benets. It is easy to organize our data
strorage manner: the Sprite
lass stores the
onguration 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;
...
}
Here the last argument owner gives the owner of the
omposite obje
t being dened, 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
ied 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 dening 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 dened 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 dening
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
ied 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 dierent 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 denition 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
onguration
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
onguration
hange. If repaintP is
false, then the repainting is not done, only the
onguration
hange is re
orded.
This feature is useful espe
ially when invoking a
onguration
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
onguration
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 denitions.
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();
In this, the rst 3 lines dened 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 dened). 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 dene
ommands to wait for spe
ied 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
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 dierent 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
dierent
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
oee 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.
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));
}
double sim::time = 0;
priority_queue< sim::ETpair, ve
tor<sim::ETpair>, sim::
ompareETpair> sim::pq;
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 ae
t the variable
ount as dened 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.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
oee shop manned by a single server. Suppose the
shop serves beverages and food, all of whi
h require some eort 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
oee 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
oee 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;
200
Mumbai 220
160
Pune
50
450
Satara
300
Kolhapur
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));
}
}
};
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
oee 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
oee 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 innite) 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 ae
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 undened. For this you should use the
value NAN supported as a part of the header le <
math>. The value NAN represents
\undened 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 dierent 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
onguration. 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
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);});
}
}
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
leftTaxiway
rightTaxiway+1+G rightTaxiway
G ... 1 0
fromGates + G toGates + G
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.
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
Exer
ises
1. Modify the simulation program to print out the average air
raft delay.
2. Dene 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. Dene 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
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
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 dierent lengths,
ompute the
onguration 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.
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
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
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
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. Dene an n n matrix
A in whi
h aij = u
fi
j
uj . Dene 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 dene 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.3 Remarks
As you experiment with NRM you might noti
e that the error norm (as dened 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 .
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
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 dierentiating 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
+
T D
*
* *
u v
du/dx dv/dx
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;
s1 = NULL; // Group 3
out << s1.use_
ount() << " " << s2.use_
ount() << endl << endl;
}
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;
}
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.
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
ied, 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, prexing 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 denitions). 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
472
Appendix E
We will dis
uss some of the less frequently used operators, and then
onsider operator over-
loading.
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 dened 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
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 prex unary operators
an be overloaded
+ - * & ! ~ ++ --
For any operator in the list above, overloading
an be done either by dening a member
fun
tion operator in the
lass of the operand taking no argument, or by dening 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 dene a member or
ordinary fun
tion operator like the prex versions. However to distinguish from the prex
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
lass iostream is used to dene 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.
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
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 dening a named fun
tion, or dening 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 dene 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
ied 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
laries that we mean a fun
tion whi
h returns an
int.
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 dened. 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
ies 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 prexing them with this->.