Notes For C Programming For BCA, MCA, BSc. MSC, BE & B.tech 1st Year

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 464

1

C P ROGRAMMING
A N I NTRODUCTION

Arun Umrao
www.sites.google.com/view/arunumrao

D RAFT COPY - GPL L ICENSING


2

Contents

1 Basic C 3
1.1 Binary Arithmetic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1.1 Symbols & Charcodes . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.1.2 Decimal to Binary . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Whole Integer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Decimal Fraction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Indexing of Binary Digits . . . . . . . . . . . . . . . . . . . . . . . 8
1.1.3 Binary To Decimal . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Whole Binary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Binary Fraction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.1.4 Memory Storage . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.2 Formatted I/O . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.2.1 Print & Scan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
printf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
sprintf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Buffer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
scanf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.2.2 Placeholders (Modifiers) . . . . . . . . . . . . . . . . . . . . . . . . 22
1.2.3 Escape Characters . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
1.2.4 Quotes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
1.2.5 Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
1.2.6 Range Operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
1.3 Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
1.3.1 Address . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Character & String Variables . . . . . . . . . . . . . . . . . . . . . 33
Integers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Integer Casting into Char . . . . . . . . . . . . . . . . . . . . . . . 38
Real Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
Float Decimals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Double Decimals . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
Long Decimals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
Long Double . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Alias Data type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Boolean . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
Declaration, Initialization & Assignment . . . . . . . . . . . . . . . 48
Float To Integer . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
Signed & Unsigned Integer . . . . . . . . . . . . . . . . . . . . . . 57
Overflow of Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
Memory Size (sizeof) . . . . . . . . . . . . . . . . . . . . . . . . . . 63
Casting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
Scope of Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
1.3.2 Qualifiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
const Qualifier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
static Qualifier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
3

extern Qualifier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
volatile Qualifier . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
auto Qualifier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
register Qualifier . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
restrict Qualifier . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
attribute & pragma . . . . . . . . . . . . . . . . . . . . . . . . . 81
1.4 C Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
1.4.1 Expression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
1.4.2 Instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
1.4.3 Unary Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
1.4.4 Binary Relation Operators . . . . . . . . . . . . . . . . . . . . . . 85
1.4.5 Comma Operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
1.4.6 Bitwise Operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
1.4.7 Logical Operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
1.4.8 Shift Operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
1.4.9 Condition & Relation Operators . . . . . . . . . . . . . . . . . . . 99
1.4.10 Lexical Comparison . . . . . . . . . . . . . . . . . . . . . . . . . . 100
1.4.11 Arithmetic Operators . . . . . . . . . . . . . . . . . . . . . . . . . 100
1.4.12 Relational Operators . . . . . . . . . . . . . . . . . . . . . . . . . . 103
1.4.13 Bit Field . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
1.5 Precedence of Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
1.5.1 Precedence of Arithmetic Operators . . . . . . . . . . . . . . . . . 114
1.5.2 Precedence of Relational Operators . . . . . . . . . . . . . . . . . . 116
1.5.3 Precedence of All Operators . . . . . . . . . . . . . . . . . . . . . . 117
1.5.4 Precedence in Assignment . . . . . . . . . . . . . . . . . . . . . . . 118
1.5.5 Unary & Binary Operators . . . . . . . . . . . . . . . . . . . . . . 118
1.5.6 Associativity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
1.6 Conditions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
1.6.1 If Condition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
1.6.2 If-else Condition . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
1.6.3 If-else-if Case . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
1.6.4 Switch & Case . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
1.6.5 Goto Keyword . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
1.6.6 Break Keyword . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
1.7 Iteration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
1.7.1 For Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
1.7.2 While Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
1.7.3 For As While . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
1.7.4 Do While . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
1.8 Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
1.8.1 Character Encoding . . . . . . . . . . . . . . . . . . . . . . . . . . 140
1.8.2 String Literal In Expression . . . . . . . . . . . . . . . . . . . . . . 140
1.8.3 String Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
strcat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
strchr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
strcmp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
strcpy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
4

strlen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
strncat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
strncmp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
strncpy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
strrchr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
strstr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
strtok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
strtod . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
1.9 Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
1.9.1 Function Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . 157
1.9.2 Function Prototype . . . . . . . . . . . . . . . . . . . . . . . . . . 161
1.9.3 Function Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
1.9.4 Function Recursion . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
1.9.5 Function As Argument . . . . . . . . . . . . . . . . . . . . . . . . . 169
1.9.6 Function Callback . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
1.9.7 Memory Function . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
mmap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
File Access Modes . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
memset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
memcpy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
memmov . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
memchr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178
memcmp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178
1.9.8 Unicode Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
1.10 Procedures & Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
1.10.1 Code Optimisation . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
1.10.2 Increments & Decrements . . . . . . . . . . . . . . . . . . . . . . . 185
1.10.3 Static Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
1.10.4 Function with Variable Arguments . . . . . . . . . . . . . . . . . . 190
1.10.5 Indirect Call of Function . . . . . . . . . . . . . . . . . . . . . . . . 192
1.10.6 Preprocessor Macros . . . . . . . . . . . . . . . . . . . . . . . . . . 193
Literals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
Tokens . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
#if, #else, #elif, #endif . . . . . . . . . . . . . . . . . . . . . . . . 195
#ifdef & #ifndef . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
#define . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
1.10.7 Type Converter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
1.11 Parsing Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
1.11.1 Array To Integer . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208
1.12 Mathematis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
1.12.1 Trigonometric Functions . . . . . . . . . . . . . . . . . . . . . . . . 210
cos, sin & tan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
acos, asin & atan . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212
cosh, sinh & tanh . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212
acosh, asinh & atanh . . . . . . . . . . . . . . . . . . . . . . . . . . 213
1.12.2 Logarithm Function . . . . . . . . . . . . . . . . . . . . . . . . . . 213
Exponential & Logarithm . . . . . . . . . . . . . . . . . . . . . . . 213
5

1.12.3 Arithmetic Function . . . . . . . . . . . . . . . . . . . . . . . . . . 214


Power . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214
Square Root . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
Floor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216
Ceiling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
Rounds Off . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218
1.12.4 Float Point Arithmetic . . . . . . . . . . . . . . . . . . . . . . . . . 220
Operators in Float Points Arithmetic . . . . . . . . . . . . . . . . 222
Astray Result . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
Double Floating Point . . . . . . . . . . . . . . . . . . . . . . . . . 224
1.12.5 Zero Crossing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
Limit At Zero . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
1.12.6 Random Number Generator . . . . . . . . . . . . . . . . . . . . . . 225

2 Array & Pointer 227


2.1 Array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227
2.1.1 Uni-Dimensional Array . . . . . . . . . . . . . . . . . . . . . . . . 227
2.1.2 Multi-Dimensional Array . . . . . . . . . . . . . . . . . . . . . . . 231
2.1.3 Array of Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
2.1.4 Array in Function . . . . . . . . . . . . . . . . . . . . . . . . . . . 249
2.1.5 String As Array . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255
2.1.6 Size of Array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258
2.1.7 Vector & Matrix . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260
2.1.8 Sparse Matrix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
2.2 Pointer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263
2.2.1 Declaring pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . 267
Assigning values to pointers . . . . . . . . . . . . . . . . . . . . . . 270
Pointer Dereferencing (Value Finding) . . . . . . . . . . . . . . . . 273
Addition of pointers . . . . . . . . . . . . . . . . . . . . . . . . . . 275
Passing of Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . 278
2.2.2 Pointers and Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . 279
Pointers to Multidimensional Arrays . . . . . . . . . . . . . . . . . 283
Pointers as Function Argument . . . . . . . . . . . . . . . . . . . . 284
Address as Function Argument . . . . . . . . . . . . . . . . . . . . 288
Pointer Equivalent to Array . . . . . . . . . . . . . . . . . . . . . . 291
2.2.3 Pointers and Text Strings . . . . . . . . . . . . . . . . . . . . . . . 295
Pointers to Function . . . . . . . . . . . . . . . . . . . . . . . . . . 297
Casting of Pointer . . . . . . . . . . . . . . . . . . . . . . . . . . . 302
Address Copying Vs Content Copying . . . . . . . . . . . . . . . . 303
2.2.4 Dangling & Wild Pointers . . . . . . . . . . . . . . . . . . . . . . . 304
2.2.5 Pointer, Variable & Address . . . . . . . . . . . . . . . . . . . . . . 305
2.2.6 Constant Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . 309
2.2.7 Memory Allocation . . . . . . . . . . . . . . . . . . . . . . . . . . . 312
Dynamic Memory Allocation . . . . . . . . . . . . . . . . . . . . . 312
Reallocate Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . 315
2.2.8 Pointer Arithmetic . . . . . . . . . . . . . . . . . . . . . . . . . . . 316
2.2.9 Pointer Address . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320
6

2.2.10 Pointer to Pointer . . . . . . . . . . . . . . . . . . . . . . . . . . . 325


int *p[ ]; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335
int **p[ ]; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
int (*p)[ ]; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337
int (**p)[ ]; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338
int *(*p)[ ]; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338
int (*p[ ])[ ]; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
int *p(); . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 340
int (*p)(); . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341
int (**p)(); . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341
int *(*p)(); . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342
int (*p())(); . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343
int (*p[ ])(); . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344
int (*p())[ ]; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345
2.2.11 Pointer Casting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346
2.2.12 Pointer as Structure . . . . . . . . . . . . . . . . . . . . . . . . . . 347

3 File & Data Structure 349


3.1 Input Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349
3.1.1 Handling File Directory . . . . . . . . . . . . . . . . . . . . . . . . 349
3.1.2 Change Directory . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349
3.1.3 FILE pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350
Locking & Unlocking a File . . . . . . . . . . . . . . . . . . . . . . 351
Reading/Scanning Directory . . . . . . . . . . . . . . . . . . . . . 353
Open a File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354
Close a File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356
Reading File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364
Writing File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378
Remove & Rename a File . . . . . . . . . . . . . . . . . . . . . . . 383
Resize a File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 386
File Pointer as Function Argument . . . . . . . . . . . . . . . . . . 386
Low Level Input/Output . . . . . . . . . . . . . . . . . . . . . . . 387
3.2 Symbol Table . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391
3.3 Data Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391
3.3.1 Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391
Nested Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404
Structure As Arguments . . . . . . . . . . . . . . . . . . . . . . . . 408
Multi-Dimensional Struct . . . . . . . . . . . . . . . . . . . . . . . 410
Return Structure from Function . . . . . . . . . . . . . . . . . . . 414
3.3.2 Enumerate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415
3.3.3 Unions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 416
3.3.4 Stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 419
Push A Value . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421
Pop A Value . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421
Array in Stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422
String in Stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 425
3.3.5 Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 425
7

Create Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 425


Delete Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426
Update Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426
Access Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426
3.3.6 Link List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 427
Linked List (Array) . . . . . . . . . . . . . . . . . . . . . . . . . . 427
Linked List (Pointer) . . . . . . . . . . . . . . . . . . . . . . . . . . 430
3.3.7 Heap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 437
Construction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 438
Add/Insert an Element . . . . . . . . . . . . . . . . . . . . . . . . 438
Remove an Element . . . . . . . . . . . . . . . . . . . . . . . . . . 439
3.3.8 Tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440
Create Tree Structure . . . . . . . . . . . . . . . . . . . . . . . . . 440
Insert Tree Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441
Display Tree Data . . . . . . . . . . . . . . . . . . . . . . . . . . . 441
Delete Tree Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . 442
3.3.9 Binary Tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 445

4 Miscellaneous 447
4.1 Error Handling Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . 447
4.1.1 clearerr function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 447
4.1.2 ferror function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 448
4.1.3 perror function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 448
4.1.4 Segmentation Fault . . . . . . . . . . . . . . . . . . . . . . . . . . . 449
4.2 Reserved Keyword . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450
4.3 Case Sensitivity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450
4.4 Commenting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451

5 Library 453
5.1 Through NetBean . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 453
5.1.1 Create Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 453
5.1.2 Link Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 454
5.2 From Command Line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 454
5.2.1 Create Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 454
5.2.2 Link Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 455
5.3 Load Library Dynamically . . . . . . . . . . . . . . . . . . . . . . . . . . . 456
8 Basic C
1.1. BINARY ARITHMETIC 9

1 Basic C

C is a technically low level programming and backbone of computer & information


technology. Every device has at least one part that functions on the platform of C.
Now we will study the basic functionality and procedure of C. C must be practiced by
every person who want to learn Computer Programming because C like procedure and
functions are used in all languages developed on C Platform (like Matlab, Octave, Scilab,
PHP, Java, Python, MySQL and Ruby etc). The compiler used in this book is ‘gcc’ in
‘cygwin’ environment. Algorithm is a prescription to solve a problem, which, provided it
is faithfully executed yields the result in a finite number of steps. Programming Gives a
means to translate the algorithm into a set of instructions that can be understood by the
computer.

1.1 Binary Arithmetic


A number that is formed by using digits 0, 1, 2, 3, 4, 5, 6, 7, 8 and 9 are called decimal
numbers. A number consists only digits 0 and 1 are called binary number. Base of decimal
number is 10, and base of binary number is 2. Some other numbers, those are used in
computers are octal and hexadecimal numbers whose base is 8 and 16 respectively. The
sequences of digits of a number system are used to form a number of that number system.
For example, sequence of digits 9, 0, 1 and 2 of decimal number system form a number
with face value 9012. Similarly, sequence of digits 1, 0, 1 and 0 of binary number system
form a number with face value 1010.
Number Digits In a number system, the distinct symbols or digits, which are used
to construct a number of the number system are called number digits of that number.
For example, in decimal form of number system, digits 0, 1, 2, 3, 4, 5, 6, 7, 8 and 9 are
used. In binary form of number system, digits 0 and 1 are used. Similarly, in octal form
of number system, digits 0, 1, 2, 3, 4, 5, 6 and 7 are used. And in hexadecimal number
system, digits 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e and f are used.
Base of Number Base of a number system is number of distinct digits present in that
number system. For example, there are ten distinct digits in decimal form of number
system. Hence its base is ‘10’. In binary form of number system, there are two distinct
digits, hence base of binary number system is ‘2’. Similarly, base of octal and hexadecimal
form of number systems are ‘8’ and ‘16’ respectively.
Place Value Place value of a digit of a number in a given number system, is digit
times to the exponent power of its place index to base of the number system. Place index
is an integer ranging from 0 to n from right to left for whole part of the number and −1
to −n from left to right for its fraction part. See the figure below:
10 Basic C

103 102 101 100 b


10−1 10−2 10−3 10−4

Figure 1.1: Place values in decimal form of number system.

In above figure, dot (·) represents to decimal symbol separating whole part from
fractional part of the given number. In decimal form of number system, the place value
at an index is 10 times larger than its right side value and 10 times lesser than its left
side value. If a given number is 213.45 then the place values of its digits are given by

2 × 102 1 × 101 3 × 100 4 × 10−1 5 × 10−2


b

2 1 3 4 5

Figure 1.2: Place values of digits of number 213.45.

In above figure, dot (·) represents to decimal symbol separating whole part (213) from
fractional part (45) of the given number 213.45.

1.1.1 Symbols & Charcodes


In human languages, symbols are scripture when pronounced by those who can identify
then gave unique sound or meaning. For example, in Hindi, character ‘ka’ gives unique
sound and meaning when it is pronounced or written by anyone. The symbols are classified
as alphabetic, numeric or special symbols etc. Alphabetic symbols are a to z, numeric
symbols are 0 to 9 and special symbols are &, #, % etc. These symbols are identified by
humans. In, computers, these symbols have no meaning. The computer communicates
using electro-magnetic waves like

A wave have two half cycles in which one is in positive y-axis side and other is in neg-
ative y-axis side. Electronic devices observe these two half cycles during communication.
The positive half cycle is denoted by ‘1’ and negative half cycle is denoted by ‘0’. Thus
all the electronic symbols are constructed by using these two digits, commonly known as
binary digits.
1.1. BINARY ARITHMETIC 11

digit 1
t
digit 0

In digital devices, communication waves are in square shape. Binary digits ‘1’ and ‘0’
are plotted in square wave form as shown below:

digit 1
t
digit 0

These two binary digits are called bits. For human machine communication, i.e.
communication between human symbols and electrics wave is done by digital coding of
the symbols. In the following table, all human readable symbols are coded from 1 to 128
with numeric base 10.

Dec Description Dec Description Dec Description


0 Null character 11 Vertical Tab 22 Synchronous idle
1 Start of Header 12 Form feed 23 End of transmission block
2 Start of Text 13 Carriage return 24 Cancel
3 End of Text 14 Shift Out 25 End of medium
4 End of Transmission 15 Shift In 26 Substitute
5 Enquiry 16 Data link escape 27 Escape
6 Acknowledgment 17 Device control 1 28 File separator
7 Bell 18 Device control 2 29 Group separator
8 Backspace 19 Device control 3 30 Record separator
9 Horizontal Tab 20 Device control 4 31 Unit separator
10 Line feed 21 Negative acknowledgement 127 Delete

Table 1.1: Non Printable Character Codes (ASCII)


12 Basic C

Dec Sym Sym Dec Sym Dec Sym Dec Sym Dec Sym Dec
32 48 0 64 @ 80 P 96 ‘ 112 p
33 ! 49 1 65 A 81 Q 97 a 113 q
34 50 2 66 B 82 R 98 b 114 r
35 # 51 3 67 C 83 S 99 c 115 s
36 $ 52 4 68 D 84 T 100 d 116 t
37 % 53 5 69 E 85 U 101 e 117 u
38 & 54 6 70 F 86 V 102 f 118 v
39 ’ 55 7 71 G 87 W 103 g 119 w
40 ( 56 8 72 H 88 X 104 h 120 x
41 ) 57 9 73 I 89 Y 105 i 121 y
42 * 58 : 74 J 90 Z 106 j 122 z
43 + 59 ; 75 K 91 [ 107 k 123 {
44 , 60 ¡ 76 L 92 \ 108 l 124 |
45 - 61 = 77 M 93 ] 109 m 125 }
46 . 62 ¿ 78 N 94 ˆ 110 n 126 ∼
47 / 63 ? 79 O 95 111 o 127

Table 1.2: Printable Character Codes (ASCII)

In above table, each symbol is coded as decimal number and this decimal code is called
character code of the given symbol. In mathematics, numbers are convertible between
different bases. For example, decimal numbers have base ‘10’ while binary numbers have
base ‘2’. Base of a number is that count upto which numeric digits are available to con-
struct a number. For decimal numbers, there are ten digits available for construction of
numbers. Similarly for binary numbers, there are two digits; for hexadecimal numbers,
there are sixteen digits and for octal numbers there are eight digits available for construc-
tion of respective numbers. A well known number conversion is decimal to binary and
vice-versa.
During communication, when we press a symbol, it is lookup into the symbol-decimal
table. The character codes of the pressed symbol is converted into equivalent binary
number. Now, a signal wave is generated representing the binary number. This signal
wave is accepted by computer assuming that it is that symbol which was pressed by user.
To understand the above statements, we will solve few problems.

Solved Problem 1.1 Draw a plot showing binary digits ‘1’ and binary digit ‘0’ assuming
wave width for one bit as one centimeter.
Solution The plot for digits ‘1’ and binary digit ‘0’ assuming wave width one cen-
1.1. BINARY ARITHMETIC 13

timeter is shown below:

1 1 1
t
0 0

Solved Problem 1.2 Using the symbol-code table, find the character code of the symbols
‘c’, ‘C’ and ‘k’.

Solution From the ASCII character table, the character codes of symbols ‘c’, ‘C’ and
‘k’ are 99, 67 and 107 respectively.

1.1.2 Decimal to Binary


As computer can understood only binary numbers hence conversion of humane under-
standable numbers into computer understandable number is required. In following sec-
tions, method of number conversion is given.

Whole Integer
If decimal number is a whole decimal number then it can be converted into binary number
by dividing it by 2 and writing remainders in reverse direction. First the number is divided
by 2 and the quotients are also subsequently divided by 2 until, quotient becomes zero.
See example of conversion of (25)10 into binary number.

25/2 12/2 6/2 3/2 1/2 0


Quotient 12 6 3 1 0
Remainder 1 0 0 1 1
Bit Order ←−

Table 1.3: Decimal to binary conversion.

Now write the remainders in reverse order. The binary equivalent to the decimal 25
is
2510 = 0110012 (1.1)

Decimal Fraction
If number is in decimal fraction, then decimal to binary conversion is take place by
multiplying fraction with two and writing whole number as binary bit and fraction again
as decimal fraction. This process undergoes until fraction becomes zero or a ordered
14 Basic C

sequence is obtained. An example of binary conversion of decimal number 0.2510 is given


below.

0.25 × 2 0.5 × 2 0.0 × 2


Result 0.5 1.0 0.0
Fraction Part 0.5 0
Whole Part 0 1
Bit Order −→

Table 1.4: Decimal fraction to binary conversion.

Now write the remainders in forward order by prefixing decimal sign ·. The binary
equivalent to the decimal fraction 0.25 is

0.2510 = 0.012 (1.2)

Indexing of Binary Digits


Binary digits are used in computer science. The normal object counting is started from
1 to n if there are object other wise objects are assumed as zero or nil. But, in computer
science, the counting is started from 0 to n not from 1 to n if there are objects otherwise
objects are assumed as NULL. In computer science zero is nil and NULL is never exist.
Hence Least Significant Bit (LSB) digits is always indexed as 0 and Most Significant Bit
(MSB) digits is indexed as n − 1 in n bits binary number. The ordered counting or place
counting of binary bits in a binary number is always started from zero index.

D7 D6 D5 D4 D3 D2 D1 D0
MSB LSB
1 1 1 1 1 1 1 1

Table 1.5: 8 bits binary number. Bits are indexed from D0 to D7 .

Solved Problem 1.3 Identify the D5 bit in the binary number 1101102.
Solution In the binary number 1101102, the D5 bit is bit 1. For more clarity, see the
below bits arrangement.

D7 D6 D5 D4 D3 D2 D1 D0
MSB LSB
0 0 1 1 0 1 1 0

Table 1.6: 8 bits binary number. Bits are indexed from D0 to D7 .


1.1. BINARY ARITHMETIC 15

Solved Problem 1.4 Convert decimal number 124 into binary number and identify the
5th bit or D4 bit from LSB side.

Solution In the decimal 124 on binary conversion gives 11111002. The 5th bit or D4
bit from LSB side is bit 1. For more clarity, see the below bits arrangement.

D7 D6 D5 D4 D3 D2 D1 D0
MSB LSB
0 1 1 1 1 1 0 0

Table 1.7: 8 bits binary number. Bits are indexed from D0 to D7 .

1.1.3 Binary To Decimal


Binary to decimal conversion of numbers is required to understand computer’s numerical
easily by humans. Binary to decimal conversion for whole and fraction binary number is
discussed in followings sections.

Whole Binary
Suppose we have a binary number 1010012 and it is to be converted into decimal equiv-
alent. Now we do following process in binary to decimal conversion.

1010012 = 1 × 25 + 0 × 24 + 1 × 23 + 0 × 22 + 0 × 21 + 1 × 20
= 32 + 0 + 8 + 0 + 0 + 1 (1.3)
= 4110

In binary to decimal conversion power of base 2 increases from zero to one less in maximum
bit numbers, i.e. if there are n bits in a binary number then power of base 2 increases
from 0 to n − 1. Zero power in base, is raised in right most bit and max power is raised
in left most bit.

Binary Fraction
Suppose we have a fraction binary number 0.1012 and it is to be converted into decimal
equivalent. Now we do following process in binary to decimal conversion.

0.1012 = 1 × 2−1 + 0 × 2−2 + 1 × 2−3


= 0.5 + 0 + 0.125 (1.4)
= 0.62510

In binary to decimal conversion power of base 2 decreases from negative one to the negative
of bits in fraction binary number, i.e. if there are n bits in a fraction binary number then
power of base 2 decreases from −1 to −n. (−1) power in base, is raised in left most bit
16 Basic C

and (−n) power is raised in right most bit. If binary number is in compound form i.e.
11010.11012 then it can be converted into equivalent decimal number by solving whole
part and fraction part separately or by commonly. Decimal conversion in separation of
whole part 110102 and fraction part 0.11012 can done by method described above. If we
have to convert compound binary number as a whole then

1010.112 = 1 × 23 + 0 × 22 + 1 × 21 + 0 × 20 + 1 × 2−1 + 1 × 2−2


= 8 + 0 + 2 + 0 + 0.5 + 0.25 (1.5)
= 10.7510

In above conversion, power of base 2 successively increases according to the number line
when we observe it from right to left.

Solved Problem 1.5 Using the symbol-code table, find the character code of the symbols
‘C’ and convert into equivalent binary number.

Solution The character code of symbol ‘C’ in decimal number is 67. Its binary
equivalent is 010000112.

Solved Problem 1.6 Using the symbol-code table, find the character code of the symbols
‘Z’ and convert into equivalent binary number and signal wave assuming wave width for
one bit as one centimeter.
Solution The character code of symbol ‘Z’ in decimal number is 90. Its binary
equivalent is 010110102. The equivalent signal waveform is given below:

1 1 1 1
t
0 0 0 0

1.1.4 Memory Storage


Binary data of computers stored in permanent memory in binary form as shown in the
following figure.

1000101000111110101011101010111010101000

This arrangement of binary digits has no meaning. This is due to mainly two reasons
(i) how many bits should be taken to reconstruct the character code which was converted
into binary digits and stored in the memory and (ii) the binary data is not readable.
It has no limiting value. To overcome these problem, binary data is grouped into fixed
number of bits. These groups are called datatypes. See the table given below:
1.1. BINARY ARITHMETIC 17

Bits Data Type Size (bytes)


1 Bit
4 Nibble
8 Byte 1
16 Short 2
32 Integer 4
64 Long, double 8

Table 1.8: Data Types.

The primary unit of memory space is byte, and each byte acts as a memory cell,
housing 8 bits data. If above memory data is arranged in bytes, then it looks like.

10001010 00111110 10101110 10101110 10101000

Though the data is arranged in cells of fixed size. But location of data is undefined.
Thus each memory cell is assigned an address which is unique location of the memory
cell.

10001010 00111110 10101110 10101110 10101000


0×51 0×52 0×53 0×54 0×55

Now we can read or write data on the memory cell which is identified by its address.
Note that, a byte is group of 8 bits, hence data types like bit and nibble are used to
access the bits within a memory cell (byte) and data types like byte, integer etc are used
to access data between the cells (bytes). Data types do not change data while reading it
from memory but they interpret it differently. For example, in the memory arrangement

10001010 00111110 10101110 10101110 10101000


0×51 0×52 0×53 0×54 0×55

if data type is byte, then it read data byte by byte. Starting from the address 0×51,
it reads binary data from one byte at address 0×51, i.e. 100010102 and convert it into
equivalent decimal number, which is 13810 . Now, computer returns character symbol
whose character code is 138. Further we can read next data bytes. If data type is
integer type, then it reads four bytes at once. So, starting from the address 0×51, it
reads binary data from four bytes at once, i.e. 100010100011111010101110101011102 and
convert it into equivalent decimal number, which is 231936375810. It can not be converted
into equivalent character symbol as it is beyond the size of characters. Note that, each
variable starts reading data from its first address and it reads data upto number of bytes
which is equal to the size of the variable data type. Hence only first byte address is
important.
18 Basic C

Solved Problem 1.7 The binary data 1001010110000101010000012 is stored in memory


from the address 0×0501. A variable of short data type access this data from the address
0×0502. What will be the value assigned to this variable?

Solution The variable of short type will read data in group of two bytes.

10010101 10000101 01000001


0×0500 0×0501 0×0502 0×0503 0×0504

So, it will read two bytes data started from the address of 0×0502. The value assigned
to this variable will be 10000101010000012 in binary or in equivalent decimal 854110.

1.2 Formatted I/O


A program can received input from its console and puts result in the console after pro-
cessing. In C, printf is used to put the formatted data in output stream and scanf is
used to receive data from input stream.

1.2.1 Print & Scan


Here we will study the inbuilt functions of C which are used to take and put data from
console. Later, we construct own functions. Here is simple C program.

1 /* Include header files , It have predefined functions . */
# include < stdio .h >
3

int main ( void ) {


5 /* print at console */
printf ( " Hello , world !\ n " ) ;
7

/* return true value */


9 return 0;
}
✆✌
When program runs, output of the program appears in console window. Here it is

Hello , world !
✆✌
In above example,

1 # include < stdio .h >
✆✌
tells to C compiler to find the standard header file stdio.h globally and include it to the
program. stdio.h contains description of standard input/output functions which we can
use to sent messages to a user or to read input from a user.

1 # include < stdio .h >
# include " stdio . h "
✆✌
1.2. FORMATTED I/O 19

If a header file is encapsulated between < and > symbols, then compiler searches the
header file in default header directory. Similarly, if the header file is encapsulated between
double quotes (“ ... ”), then compiler searches the header file in local program/project
directory.

int main ( void )
✆✌
is the main function which is automatically invoked when program runs. It is also an
entry point of the program, from where a program starts running. In other words, the
mnemonic instructions of program are executed from the beginning of address of main()
function. Prefix int to main() function has meaning that main() function will return
an integer to the operating system when it is finished. Though the default return value
of main() function is integer but return value as void is also acceptable. The returns
value of main() function tells the OS about the run state of the program. On successful
complete run of the program, it returns 0 otherwise it returns error code. The compiler
shows warning when return value from the main function is not integer.

1 printf ( " Hello , world ! " ) ;
✆✌
is the statement that actually puts the message to the screen. printf is the formatted
printing function that is declared in the header file stdio.h.

1 return 0;
✆✌
will return zero to the operating system. ‘Return of 0 is indication of successful execution
of program. Return value other than ‘0’ indicates run failure or error in execution of
program. C uses conventional code grouping structure. A function or a code block are
grouped by curly braces, ie {...}. All the variable defined inside the group {...} have local
scope. A semicolon is used to terminate the line.

1 /* The main function */
int main ( void ) {
3 /* This is the beginning of a ‘ block ’ */
int i = 6; /* It is first variable of this ‘ block ’ */
5 { /* Start of new block . */
/* This is a new ‘ block ’, and because it ’s *
7 * a different block it has its own scope . */

9 /* This is also a variable called ‘i ’, *


* but in a different ‘ block ’, because *
11 * it ’s in a different ‘ block ’ than the *
* old ’i ’, it doesn ’t affect the old one ! */
13 int i = 5;
printf ( " % d \ n " , i ) ; /* Prints ‘5 ’ in the screen */
15 } /* End of new block . */

17 /* Now we ’ re back into the old block */


printf ( " % d \ n " , i ) ; /* Prints ‘6 ’ in the screen */
19

return 0;
20 Basic C

21 }
✆✌
Also see the example given below.

1 # include < stdio .h >

3 int main () {
int x = 1; /* Original x */
5

printf ( " x in outer block : % d \ n " , x ) ;


7 { /* Begin of new block . */
int x = 2; /* New x , hides original x */
9 printf ( " x in inner block : % d \ n " , x ) ;
} /* End of new block . */
11 printf ( " x in outer block : % d \ n " , x ) ;
for (; x < 5; x ++) { /* Original x */
13 int x = 10; /* New x , hides original x */
x ++;
15 printf ( " x in while loop : % d \ n " , x ) ;
}
17 printf ( " x in outer block : % d \ n " , x ) ;
return 0;
19 }
✆✌

x in outer block : 1
x in inner block : 2
x in outer block : 1
x in while loop : 11
x in while loop : 11
x in while loop : 11
x in while loop : 11
x in outer block : 5
✆✌

printf
This function is used to print stuff in console output. Use of this function is shown in the
example given below:

# include < stdio .h >
2 int main ( void ) {
printf ( " Hello , world !\ n " ) ;
4 return 0;
}
✆✌
On execusion of the program output will be looked like

Hello , world !
✆✌
1.2. FORMATTED I/O 21

sprintf
It composes a formatted string and instead printing it in console. It copies string into
buffer. It takes values of third parameter in accordance to its second parameter and
converts result into string (i.e. sequece of characters). Now, finally, the converted string
is copied into the buffer parameter. The syntax of this function is given below:

1 n = sprintf ( < buff > , < format > , < inputs >)
✆✌
The size of the buffer should be large enough so that it can contain the entire resulting
string. A terminating null character is automatically appended after the content. If
formatted string is copied into buffer successfully, length of copied string is returned by
the function. On failure negative integer is returned.

1 # include < stdio .h >

3 int main () {
char buffer [20];
5 int n , a = 2 , b = 3;
n = sprintf ( buffer , " % d * % d = % d " , a , b , a * b ) ;
7 printf ( " Length of string [% s ] is % d .\ n " , buffer , n ) ;
return 0;
9 }
✆✌

Length of string [2 * 3 = 6] is 9.
✆✌
Same example with change in format of inputs, gives completely different result.

1 # include < stdio .h >

3 int main () {
char buffer [50];
5 double n , a = 2 , b = 3;
n = sprintf ( buffer , " % f * % f = % f " , a , b , a * b ) ;
7 printf ( " Length of string [% s ] is % f .\ n " , buffer , n ) ;
return 0;
9 }
✆✌

Length of string [2.000000 * 3.000000 = 6.000000] is 30.000000.
✆✌
Here, decimal zeros are also converted into their respective characters. In the following
example, sprintf function replaces the desired character or string with supplied character
or string. In this example recursive replacement of a character or string takes places until
all characters are replaced.

1 # include < stdio .h >
# include < string .h >
3

int main ( int argc , char * argv [ ]) {


5 char st [100] = " This is my string . " ;
22 Basic C

char r_it [2] = " s " ;


7 char repl [12] = " 1.2 " ;
char buffer [4096];
9 char * ch ;
// printf (" b :% s \ n " , st ) ;
11 while ( ch = strstr ( st , r_it ) ) {
strncpy ( buffer , st , ch - st ) ;
13 // printf (" d :% s \ n " , buffer ) ;
buffer [ ch - st ] = 0;
15 sprintf ( buffer + ( ch - st ) , " % s % s " , repl , \
ch + strlen ( r_it ) ) ;
17 if ( ch != NULL )
strcpy ( st , buffer ) ;
19 }
printf ( " The makeup string is :\ n % s " , buffer ) ;
21 return 0;
}
✆✌

Thi 1.2 i 1.2 my 1.2 tring .
✆✌
This makeup of string is very useful in the mathematical computation. In algebraic
equations, the variables and constants are required to be replaced by their numerical
values.

Buffer
“Buffer” is one of the common words used in C programs. Now a question rises about the
buffer, its constitution and its applications. Buffer is specific region of memory where data
is stored temporarily for internal processes and after processes it is flushed in instream
or outstream of the system. For example, consider a small program,

1 # include < stdio .h >
# include < stdlib .h >
3

int main ( int argc , char ** argv ) {


5 int i , j ;
i = 10;
7 j = 2* i ;
return 0;
9 }
✆✌
in which two integer type variables ‘i’ and ‘j’ stores value 10 and 20. We want to get
output be printed in output console as

10 ,20
✆✌
Here, first we have to store value of ‘i’ temporarily in memory but should not be
appeared in output console. For this, we have to create a memory array space of sufficient
size (here 10 bytes long).
1.2. FORMATTED I/O 23


1 # include < stdio .h >
# include < stdlib .h >
3

int main ( int argc , char ** argv ) {


5 char buff [10];
char tb [4];
7 int i , j ;
i = 10;
9 return 0;
}
✆✌
The memory space shall be looked like,

buff

0×40 0×41 0×42 0×43 0×44 0×45 0×46 0×47 0×48 0×49

Now, store value of ‘i’ in this created memory space at the beginning of the buff
pointer.

# include < stdio .h >
2 # include < stdlib .h >

4 int main ( int argc , char ** argv ) {


char buff [10]; // space of 11 bytes
6 char tb [4];
int i , j ;
8 i = 10;
sprintf ( tb , " % d " , i ) ; // formatted string ’10 ’
10 strncpy ( buff , tb , 4) ; // copy into buff from tb
return 0;
12 }
✆✌
sprintf function converts an integer value into sequence of one byte long characters. For
example, 4 bytes long integer, i.e. ‘10’ is converted into string of characters ‘1’ and ‘0’
respectively. Note that, previously, integer ‘10’ occupies four bytes as it was an integer
value, now occupies only two bytes as it is converted into sequence of characters depicting
a strings. The memory space shall be looked like,

buff
00000001 00000000

0×40 0×41 0×42 0×43 0×44 0×45 0×46 0×47 0×48 0×49

Now, store comma after the memory cell where value of ‘i’ is stored in the buffer
memory as desired output is required.

# include < stdio .h >
24 Basic C

2 # include < stdlib .h >

4 int main ( int argc , char ** argv ) {


char buff [10]; // space of 11 bytes
6 char tb [4];
int i , j ;
8 i = 10;
sprintf ( tb , " % d " , i ) ;
10 strncpy ( buff , tb , 4) ;
sprintf ( tb , " % c " , ’ , ’) ; // append comma
12 strcat ( buff , tb ) ; // concatenate string
return 0;
14 }
✆✌
The memory space shall be looked like,

buff
00000001 00000000 00101100

0×40 0×41 0×42 0×43 0×44 0×45 0×46 0×47 0×48 0×49

Now, store value of 2 × i after the memory cell where character comma is stored in
memory.

# include < stdio .h >
2 # include < stdlib .h >

4 int main ( int argc , char ** argv ) {


char buff [10]; // space of 11 bytes
6 char tb [4];
int i , j ;
8 i = 10;
sprintf ( tb , " % d " , i ) ;
10 strncpy ( buff , tb , 4) ;
sprintf ( tb , " % c " , ’ , ’) ;
12 strcat ( buff , tb ) ;
sprintf ( tb , " % d " , 2 * i ) ;
14 strcat ( buff , tb ) ; // append ’20 ’
return 0;
16 }
✆✌
The memory space shall be looked like,

buff
00000001 00000000 00101100 00000010 00000000

0×40 0×41 0×42 0×43 0×44 0×45 0×46 0×47 0×48 0×49

Our buffer of desired shape is generated. Now, it can be flushed into output stream
so that, it may appear in output console.
1.2. FORMATTED I/O 25


# include < stdio .h >
2 # include < stdlib .h >

4 int main ( int argc , char ** argv ) {


char buff [10]; // space of 11 bytes
6 char tb [4];
int i , j ;
8 i = 10;
sprintf ( tb , " % d " , i ) ;
10 strncpy ( buff , tb , 4) ;
sprintf ( tb , " % c " , ’ , ’) ;
12 strcat ( buff , tb ) ;
sprintf ( tb , " % d " , 2 * i ) ;
14 strcat ( buff , tb ) ;
printf ( " % s \ n " , buff ) ; // get buffer string
16 return 0;
}
✆✌
The desired output is

10 ,20
✆✌

scanf
On simplest invocation, the scanf format string holds a single placeholder representing
the type of value that will be entered by the user. scanf examines the input characters
from input stream and ignores space, tab, newline, enter and for feed characters etc.

1 # include < stdio .h >

3 int main ( void ) {


int a ;
5 printf ( " Write an integer : " ) ;
/* & operator is used to assign *
7 * address to the integer value . */
scanf ( " % d " , & a ) ;
9 printf ( " Integer value entered is % d .\ n " , a ) ;
return 0;
11 }
✆✌
Output of the programm is

Write one integer value :1
Integer value passed by you is 1.
✆✌
If a string is scanned by using scanf, ‘&’ operator is not prefixed to the character
variable. A utility program, that is not designed with printf and scanf mechanism, when
it is compiled and run then what ever is written in the output console in a line is read
and scanned by the utility. To terminate an input line in output console, enter key is
26 Basic C

pressed. To get output Ctrl+Z or Ctrl+C or Ctrl+X is pressed. If scanf is used to scan
a string or an array to the character variable ‘str’, then it is used as

scanf ( " % s " , str )
✆✌
It is equivalent to array scanning

1 scanf ( " % s " , & str [0])
✆✌
If the function is used like

1 scanf ( " % s " , & str )
✆✌
then to scanf, string is passed to a pointer-to-char[256], but it points to the same place.
As scanf stops input stream when it encounters with tab, newline, enter etc. Similarly,
when scanf starts scanning a string having with white spaces then scanf stops reading
string when it encounters white space. See the example below:

1 # include < stdio .h >

3 int main ( int argc , char * argv [ ]) {


char str [10];
5 printf ( " Enter string : " ) ;
int n = scanf ( " % s " , str ) ;
7 printf ( " Status and string is := > " ) ;
printf ( " % d : % s \ n " , n , str ) ;
9 return 0;
}
✆✌

Enter string : arun kr
Status and string is := > 1 : arun
✆✌
To overcome this problem, scanf is used as

scanf ( " %[^ < input terminating character >] " , < var >) ;
✆✌
Here, less than and greater than signs represent beginning and ending of terminating
character. The line terminating character must be preceded by carat character ‘ˆ’ and
both should be enclosed in square braces. See the example below

1 # include < stdio .h >

3 int main ( int argc , char * argv [ ]) {


char str [10];
5 printf ( " Enter string ending with ~ : " ) ;
/* Scan the string until ~ not found . */
7 int n = scanf ( " %[^~] " , str ) ;
printf ( " Status and string is := > " ) ;
9 printf ( " % d : % s \ n " , n , str ) ;
return 0;
11 }
✆✌
1.2. FORMATTED I/O 27

The input string on console is “i am king∼” and output is printed as



Enter string ending with ~ : i am king ~
Status and string is := > 1 : i am king
✆✌
scanf also accepts escape characters for termination of inputs. When escape character
is found by scanf, it stops scanning of inputs. See the example given below:

# include < stdio .h >
2

int main ( int argc , char * argv [ ]) {


4 char str [30];
printf ( " Enter string & press enter key : " ) ;
6 /* Scan the string until new line *
* escape character is not found . */
8 int n = scanf ( " %[^\ n ] " , str ) ;
printf ( " Status and string is := > " ) ;
10 printf ( " % d : % s \ n " , n , str ) ;
return 0;
12 }
✆✌

Enter string & press enter key : This is my key
Status and string is := > 1 : This is my key
✆✌
Another example with tab escape character, which is used as termination of input for
scanf function.

# include < stdio .h >
2

int main ( int argc , char * argv [ ]) {


4 char str [30];
printf ( " Enter string & press enter key : " ) ;
6 /* Scan the string until tabular *
* escape character is not found . */
8 int n = scanf ( " %[^\ t ] " , str ) ;
printf ( " Status and string is := > " ) ;
10 printf ( " % d : % s \ n " , n , str ) ;
return 0;
12 }
✆✌

Enter string & press enter key : This is my string
Status and string is := > 1 : This is
✆✌
Asterisk character ‘*’ when placed between the ‘%’ sign and typedef character then the
corresponding input is ignored.

# include < stdio .h >
2

int main ( int argc , char * argv [ ]) {


4 int i , j , k ;
28 Basic C

printf ( " Enter three integers with spaces : " ) ;


6 scanf ( " % d % d %* d " , &i , &j , & k ) ;
printf ( " Integers are \ n " ) ;
8 printf ( " % d \ t % d \ t % d \ n " , i , j , k ) ;
return 0;
10 }
✆✌

Enter three integers with spaces : 12 58 4
Integers are
12 58 0
✆✌
As third input ‘k’ is ignored by scanf hence address of the ‘k’ variable or 0 is printed
rather than its value.

1.2.2 Placeholders (Modifiers)


Placeholders are group of symbol(s) and are used to put the values at the place of place-
holder as per specified modifiers. For example, ‘%d’ is used to put integers, ‘%ld’ for long
integers, ‘%lli’ for long long integer, ‘%f’ for float integers, ‘%lf’ for double integers, ‘%c’
for characters, ‘%s’ for strings and ‘%x’ for hexadecimal.

1 # include < stdio .h >

3 int main ( void ) {


int i ;
5 for ( i = 0; i <2; i ++)
printf ( " Integer value is % d .\ n " , i ) ;
7 return 0;
}
✆✌
Output of above script is

Integer value is 0.
Integer value is 1.
✆✌
Integer can also be written in its equivalent ascii character. To do this we have to just
change the integer modifier ‘%d’ by character modifier ‘%c’.

# include < stdio .h >
2

int main () {
4 int i ;
for ( i = 65; i <= 68; ++ i ) {
6 printf ( " Integer % d is equivalent to : % c . " , i , i ) ;
printf ( " \ n " ) ;
8 }
}
✆✌
Output of above script is
1.2. FORMATTED I/O 29

Symbolic Constant Represents


%a Floating-point number, hexadecimal digits and p-
notation.
%A Floating-point number, hexadecimal digits and P-
notation.
%c Single character.
%d Signed decimal integer.
%e Floating-point number in e-notation form.
%E Floating-point number in e-notation form.
%f Floating-point number in decimal notation form.
%g If the exponent is less than 4 or greater than or equal
to the precision %e used otherwise %f is used.
%G If the exponent is less than 4 or greater than or equal
to the precision %E used otherwise %F is used.
%i Signed decimal integer.
%o Unsigned octal integer.
%p A pointer.
%s Character string.
%u Unsigned decimal integer.
%x Unsigned hexadecimal integer using hex digits 0f.
%X Unsigned hexadecimal integer using hex digits 0F.
%% Prints a percent sign.

Table 1.9: Conversion specifiers.


30 Basic C


Integer 65 is equivalent to : A .
Integer 66 is equivalent to : B .
Integer 67 is equivalent to : C .
✆✌
In C, modifiers are used to print formatted outputs. A modifier ‘%s’ simply puts the
string by creating space equal to the length of string. If this modifier is redefined like
‘%20s’ (a positive integer between % and ‘s’ symbols), then space for 20 characters is
created. If string length is less than 20 characters then ‘ ’ (space) is prefixed to the string
to increase its length to 20. If number in modifier is less than the length of string then
nothing is done.

1 # include < stdio .h >
# include < string .h >
3

int main () {
5 printf ( " \"% s \" secured numbers \"% d \"\ n " , " Arun Kumar " , 100) ;
printf ( " \"%20 s \" secured numbers \"%5 d \"\ n " , " Arun Kumar " , 100) ;
7 return 0;
}
✆✌

" Arun Kumar " secured numbers "100"
" Arun Kumar " secured numbers " 100"
✆✌
In case of string modifier, prefixed spaces can not be filled by any other character. In
case of numeric modifier, if a ‘.’ (ie full stop) is placed just after the ‘%’ symbol then
prefixed space is filled by ‘zero’ as shown in example below.

# include < stdio .h >
2 # include < string .h >

4 int main () {
printf ( " \"%5 s \" secured numbers \"%5 d \"\ n " , " Arun Kumar " , 100) ;
6 printf ( " \"%.20 s \" secured numbers \"%.5 d \"\ n " , " Arun Kumar " ,
100) ;
return 0;
8 }
✆✌

" Arun Kumar " secured numbers " 100"
" Arun Kumar " secured numbers "00100"
✆✌
The same output is found when space specifier is prefixed by zero. For example,

# include < stdio .h >
2

int main ( void ) {


4 printf ( " %05 d \ t %0.5 d \ n " , 100 , 200) ;
return 0;
6 }
✆✌
1.2. FORMATTED I/O 31


00100 00200
✆✌
For numeric modifiers, total spaces and filled space can also be used simultaneously if
modifier is modified like ‘%10.6d’. Here number ‘10’ will create 10 spaces (field of length
10) for placing a number and if digits in number is less than ‘6’ then ‘0’ will be prefixed
with the number.

1 # include < stdio .h >
# include < string .h >
3 int main () {
int i ;
5 printf ( " %5 s %10 s %10 s \ n " , " Num " , " Square " , " Cubic " ) ;
for ( i = 90; i < 92; i ++) {
7 printf ( " %5.3 d %10.6 d %10.6 d \ n " , i , i *i , i * i * i ) ;
}
9 return 0;
}
✆✌

Num Square Cubic
090 008100 729000
091 008281 753571
✆✌

1 # include < stdio .h >
# include < limits .h > // integer limits
3 # include < float .h > // floating - point limits

5 int main ( void ) {


printf ( " Biggest int : % d \ n " , INT_MAX ) ;
7 return 0;
}
✆✌

Biggest int : 2147483647
✆✌
There are several methods of modifier conversions. Modifiers accept bits equivalent to
their size. Other bits during the modifier conversion is truncated.

1 # include < stdio .h >
# define NUM 61000
3

int main ( void ) {


5 printf ( " Num as int , short int and char : %d , % hd , % c \ n " ,
NUM , NUM , NUM ) ;
7 return 0;
}
✆✌

Num as int , short int and char : 61000 , -4536 , H
✆✌
32 Basic C

‘+’ in placeholders prints a plus sign if the value is positive. ‘-’ causes left justify to
the result. Single Quotes (’) Separate the digits into groups as specified by the locale
specified. ‘O’ pads the field with zeros instead of spaces.

1 # include < stdio .h >

3 int main ( void ) {


printf ( " |% -10 d |%10 d |% -5 d |\ n " , 500000 , -1000 , 200) ;
5 printf ( " |%+10 d |% -10 d |%05 d |\ n " , 500000 , -1000 , 200) ;
printf ( " |% ’10 d |%10 d |% -5 d |\ n " , 500000 , -1000 , 200) ;
7 return 0;
}
✆✌

|500000 | -1000|200 |
| +500000| -1000 |00200|
| 500000| -1000|200 |
✆✌
There is a common error that arises from the format mismatch. for example, when we try
to print an integer as float without casting, compiler shows warning of mismatch format
and it gives strange output. See the example below:

1 # include < stdio .h >

3 int main ( void ) {


int a =10 , b ;
5 b = a /7;
printf ( " % f " ,b ) ;
7 return 0;
}
✆✌

0.00000
✆✌
This is why, to prevent the format mismatch error, we should either cast the variable or
should use proper variable declarations.

1.2.3 Escape Characters


Escape characters are used to perform action even if they are used as string. For example

1 # include < stdio .h >
int main ( void ) {
3 printf ( " Hello , world !\ n " ) ;
return 0;
5 }
✆✌
\n at the end of printf function would add a new line after “Hello world!”. The output
of the program is

Hello , world !
✆✌
1.2. FORMATTED I/O 33

Other escape characters are

Escape Character Hex Value Meaning


\a 07 Add CPU alert
\b 08 Backspace
\t 09 Adding a tab
\n 0A Start a new line
\v 0B Vertical tab
\f 0C Form feed
\r 0D Carriage return
\" 22 Double quote (”)
\’ 27 Single quote (’)
\? 3F Question mark (?)
\\ 5C Backslash (\)

1.2.4 Quotes
Character inside single quote (’) represents its character code in the machine. For example
‘A’ is equivalent to ‘65’ of the machine code.

# include < stdio .h >
2 # include < stdlib .h >

4 int main ( void ) {


printf ( " % d " , ’A ’) ;
6 return EXIT_SUCCESS ;
}
✆✌

65
✆✌
A multi-character string constants can be used inside the single quotes (‘ ’) while assigning
the value to an integer variable. First, all characters are converted into their equivalent
machine codes, then they are put in memory space one by one in their binary equivalent
form. While copying, characters are taken from the right to left direction and put in
four bytes memory space from right to left respectively (this method of computation is
machine dependent). After that, corresponding 4 bytes long binary sequence pointed by
the declared variable is converted into equivalent number and assigned to the declared
integer variable. See the example below:

1 # include < stdio .h >

3 int main ( void ) {


34 Basic C

/* Declare i as integer */
5 int i = ’ aa ’;
printf ( " Value of i is : % d \ n " , i ) ;
7 return 0;
}
✆✌
The value ‘aa’ is stored in memory as shown below:
‘a’ ‘a’
01100001 01100001

The decimal equivalent of binary sequence 01100001 01100001 is 24929. The output
of above program is

Value of i is : 24929
✆✌
The effective length of single quotes string is the size of data type of the declared
variable. For integer, it is four bytes. So only first four bytes of string are assigned to
variable i in the following example, rest of values are not accepted.

1 # include < stdio .h >

3 int main ( void ) {


/* Declare i as integer */
5 int i = ’ aabb ’;
printf ( " Value of i is : % d \ n " , i ) ;
7 return 0;
}
✆✌
Single quoted string, ‘aabb’, is stored in memory as shown below:
‘a’ ‘a’ ‘b’ ‘b’
01100001 01100001 01100010 01100010

The output of above program after computing the four bytes long binary sequence is

Value of i is : 1633772130
✆✌

1 # include < stdio .h >

3 int main ( void ) {


/* Declare i as integer */
5 int i = ’ aabbcc ’;
printf ( " Value of i is : % d \ n " , i ) ;
7 return 0;
}
✆✌
1.2. FORMATTED I/O 35

Single quoted string, ‘aabbcc’, is stored in memory as shown below:


‘a’ ‘a’ ‘b’ ‘b’ ‘c’ ‘c’
01100001 01100001 01100010 01100010 01100011 01100011

The output of above program after computing the four bytes long binary sequence is

Value of i is : 1650615139
✆✌
Notice that, here as shown in above figure, in character to integer computation takes
only those four bytes which are started from the pointer of ‘i’. Rest are neglected. Char-
acter inside double quote (”) represents to a array of character i.e. a string.

1.2.5 Comments
Commenting is most useful feature of the C programming. It is used to write comments
before or after a function or variable. Stuff within the commenting delimiters is ignored
during compilation of the program. There are two type of commenting delimiters. First,
single line commenting delimiter and second, multi-line commenting delimiter. For single
line commenting ‘//’ is used and for multi-line commenting ‘/* ... */’ is used.

1 # include < stdio .h >
int main ( void ) {
3 /* Here printf prints string multiple times .*
* Loop is used for multiple output lines . */
5 for ( ix =1; ix <=2; ix ++) {
printf ( " % d - Hello , world ! " , ix ) ;
7 }
return 0;
9 }
✆✌
The output of above program is

1 - Hello , world !
2 - Hello , world !
✆✌

1.2.6 Range Operator


C language supports declaration of range by using ‘...’ operator. For example, range
from 1 to 10 is declared as “1 ... 10”. The range operator may be used either with case
statement or in definition of the function arguments. See the example below:

# include < stdio .h >
2

int main () {
4 int i = 5;
switch ( i ) {
6 case 1 ... 10:
36 Basic C

printf ( " Within range from 1 to 10.\ n " ) ;


8 break ;
default :
10 printf ( " Not supposed .\ n " ) ;
break ;
12 }
}
✆✌

Within range from 1 to 10.
✆✌

1.3 Variables
Variables are multicharacter names used to refer to some locations in memory that holds
a value to which we are working. Variables are multicharacter names used to refer to
some locations in memory that holds a value to which we are working. A data type is
type of data that can be assigned to a variable. We know that data is stored in memory
in groups, commonly known as bytes. When a small number like, 20 or 30 is stored, it
consumes hardly one byte as they are binary equivalent to 10100 or 11110 respectively.
So, data can be easily read or write in the data memory byte.

0×20 0×21 0×22 0×23 0×24


00010100 00011110
i = 20 i = 30

If number is large, say 1024, then it needs two bytes memory space as it is binary
equivalent to 10000000000, which is spread between two bytes.

0×20 0×21 0×22 0×23 0×24


00000100 00000000
i = 1024

In C, to deal with this data span, grouping of memory bytes is allowed. This grouping
is called data type. For example, single memory byte is said as character data type.
Group of two bytes is called short data type, group of four bytes is called integer data
type etc. Grouping of bytes is fixed to maintain system independent uniformity and as
the number of bytes in a group increases, group able to store larger binary data. Note
that, data in each type of group is read and write at once. For example, binary data
101100010111010001010 spread in three bytes.

0×20 0×21 0×22 0×23 0×24


00110110 00101110 10001010
i = 9842186
1.3. VARIABLES 37

If this is integer type data then each time all these bits are read at once and will be
converted into decimal number which is 9842186. Any data type does not allow partial
read or write of data. The datatypes in C are char -one byte long, int -four bytes long,
float -four bytes long and double-eight bytes long. long data type is used to change the
byte length of float and double. The derived datatypes are arrays, structure, pointer,
function etc. The short, long, signed and unsigned are used as type modifier. Variables
are not values by itself but points to values. A variable is equivalent to its assigned value.
A variable may be alphanumeric name with underscore character. First numeric character
of a variable name is not acceptable. Spaces and special characters which are reserved
for internal operations of C are illegal. Similarly, use of comma, dot, symbol of question
mark, symbols reserved for relation operations, symbols reserved for bitwise operations,
colon and line terminating symbol are also considered as illegal if used in variable names.
Key words specially reserved for internal programming of C, can not be used like variable
name. A list of reserved keyword is given in section 4.2.

1 int A1 ; // Legal and acceptable .
int 1 A ; // Illegal , first character is numeric
3 int A_1 ; // Legal , _ is acceptable
int A$1 ; // Legal , $ is not reserved character
5 int A #1; // Illegal , # reserved for header inclusion
int A 1; // Illegal , space is not acceptable
7 int for ; // Illegal , for is reserved keyword
✆✌
A variable declared once can not be re-declared again within the same scope. Scope of
a variable is segment of a code, from where variable is accessible. By default, a local
variables get garbage value and global variables get a value 0 by default on declaration.
Sometime, words, “argument” and “parameter” are used in the C programming. The
word “argument” denotes the value that is passed to a function whereas word “parameter”
denotes the name by which the value is referred to in the body of the function.

1.3.1 Address
A most commonly used word in C programming is ‘address’. By definition, “address” is
the location of memory where either data is stored or from where data is retrieved. An
address is a multibytes value that refers to a certain memory location rather than the
value stored at that location. Take a memory map of matrix 10 × 8 size as shown below:
Low bytes
0×00 0×01 0×02 0×03 0×04 0×05 0×06 0×07
0×00 11 12 13 14 15 16 17 18
0×01 21 22 23 24 25 26 27 28
High bytes

0×02 31 32 33 34 35 36 37 38
0×03 41 42 43 44 45 46 47 48
0×04 51 52 53 54 55 56 57 58
0×05 61 62 63 64 65 66 67 68

Here, memory addressed are two bytes long and it depends on system to system. The
38 Basic C

first byte represents to high byte (i.e. rows in above matrix) and second byte represents
to low byte (i.e. column in the above matrix). For example an address 0×0304 represents
to the memory cell at 4th row and 5th column. This value indicates to location of memory
not to value at that location. From the above matrix, at 4th row and 5th column cell,
value stored is 45 not 0×0304 (address). In C we do not deals directly with addresses but
a variable name is assigned to the address. For example, if a variable

1 int i = 45;
✆✌
is declared and assigned a value equal to encircled value in above memory matrix. For
this value, address of variable ‘i’ shall be 0×0304. Address assigned to variable is always
hidden and can be retrieved by using addressof (‘&’) symbol.

1 # include < stdio .h >

3 int main () {
unsigned int i =45;
5 printf ( " % x " , & i ) ;
return 0;
7 }
✆✌

0304
✆✌
Here address variable is of 2 bytes long. Note that address of operator can not be used
with constants and variable that is declared using register storage class. A question rises
here that why address is assigned to a variable not the value itself. Its answer is, value
assigned to variable is of any size and for long values, it is impossible to assign directly
to the variable. This is why, pointers or variables are let to point the address the first
byte of the memory location where data is stored.
Str Low bytes
0×00 0×01 0×02 0×03 0×04 0×05 0×06 0×07 0×08 0×09
0×00
High bytes

0×01
0×02 T w o P e n s \0
0×03
0×04
0×05

Assume a variable ‘Str’ which is assigned a string “Two Pens”. This is eight bytes
long data. So a variable can not store this data directly. Therefore, the string is stored in
the temporary memory as shown in above figure. The variable ‘Str’ points to first byte
of the string, i.e. to ‘T’. The scope of ‘Str’ variable ended at the next null char ‘\0’. The
memory address of ‘T’ is 0×0201. Hence, variable ‘Str’ points to memory address 0×0201
from where the string started and ‘Str’ does not points to the string itself.
1.3. VARIABLES 39

Character & String Variables


char is used to initialize a character or character string. A char data type variable which
can be initialized only for one character is declared and initialized as

1 /* Declaration . */
char c ; /* Char variable one byte long */
3 /* Declaration & Initializati o n . */
char c = ’K ’; /* Single quote one byte long value . */
✆✌
Character string can be initialized as an array or pointer. The size of char data type is 1
byte. In following figure, the memory byte B[3] is reserved for character variable c (value
stored at this memory byte is K) and memory byte B[4] is reserved for character variable
s (value stored at this memory byte is L).

B[2] B[3] B[4] B[5] B[6] B[7] B[8] B[9] B[10] B[11]

K L
c s

In case of character string, as shown in the syntax given below,



char * s = " abcd " ;
✆✌
variable s is a pointer and points to the address of first element, i.e. ‘a’ of the string
“abcd”.

B[2] B[3] B[4] B[5] B[6] B[7] B[8] B[9] B[10] B[11]

a b c d
s

The memory location used to store this string is from B[5] to B[8]. B[5] stores to first
character, ‘a’ of the string, B[6] stores to second character, ‘b’ of the string, B[7] stores
to third character, ‘c’ of the string and B[8] stores to fourth character, ‘d’ of the string.
By default, a char is signed unless unsigned keyword is not used.

1 /* Group of characters in double quotes , i . e . string */
char * < var name >= " This is string . " ;
3 char < var name >[ ]= " This is string . " ;
✆✌

1 # include < stdio .h >

3 int main () {
/* Single quote to single char . */
5 char c = ’a ’;
/* Double quote to single char . */
7 char ch [2] = " b " ; /* String size is 2. One byte for b *
* and one byte for null terminator */
9 char * s = " This is my string . " ; /* Pointer to string . */
40 Basic C

printf ( " c is % c \ n " , c ) ; /* Print char */


11 printf ( " ch is % s \ n " , ch ) ; /* Print string */
printf ( " s is % s \ n " , s ) ; /* Print string . */
13 return 0;
}
✆✌

c is a
ch is b
s is This is my string .
✆✌
A single character when it is in single quote is consider as a character while the same
character when is in double quote, it is considered as a string. A group of characters has
string length, equal to one more to the number of character. The last byte of string is for
string terminator ‘\0’. A char variable without initialization stores null character.

1 # include < stdio .h >

3 int main () {
/* Declare char variable . Not initialized . */
5 char * ch ;
printf ( " Value of ch : % s \ n " , ch ) ;
7 return 0;
}
✆✌

Value of ch : ( null )
✆✌
The null terminator terminates a string. Value to a character data type may be assigned
by two ways. One, by using bymbol and other by using equivalent character code. See
the example below:

1 # include < stdio .h >

3 int main () {
char c [5] , s [5];
5 c [0]=0; /* Assign null character by *
* using char code value . */
7 printf ( " % s " ,c ) ;
s [0]= ’ \0 ’; /* Assign null character by *
9 * using single quoted symbol . */
printf ( " % s " ,s ) ;
11 return 0;
}
✆✌
Output of above program is null or empty string. See another example, in which character
array is initialized with empty string (NOT NULL). Remember that ‘\0’ and “\0” are both
same as single backslash is used to represent escape characters. To print the backslash
symbol at output stream, it is used in double, i.e. “\\”.

# include < stdio .h >
1.3. VARIABLES 41

int main () {
4 char c [5] , s [5] , s2 [5];
c [0]=0; // Assign null char by using char code value .
6 printf ( " % s " ,c ) ;
s [0]= ’ \0 ’; // Assign null char by using single quoted symbol .
8 printf ( " % s " ,s ) ;
s2 [0]= " \0 " ; /* Assign null character by using double *
10 * quoted backslash and 0 ( escape character ) . */
printf ( " % s " , s2 ) ;
12 return 0;
}
✆✌
NULL or empty string is also represented by “” (nothing within double quote symbols).

1 # include < stdio .h >

3 int main () {
/* Variable initialized with EMPTY value . */
5 char * ch = " " ;
/* Prints empty character . */
7 printf ( " ch as character : % s \ n " , ch ) ;

9 /* Prints integer value . Here empty character has *


* charcode 0. It is not ZERO char of charcode 48. */
11 printf ( " ch as integer : % d \ n " , * ch ) ;
return 0;
13 }
✆✌

ch as character :
ch as integer : 0
✆✌
Though the compiler assigned dynamically available memory address to the pointer type
variable declaration, yet we can assign designated address to the variable as shown below:

# include < stdio .h >
2 # include < stdlib .h >

4 int main () {
char value = *( char *) 0 xA0008 ;
6 printf ( " % c " , value ) ;
return 0;
8 }
✆✌
The output of this program may or may not correct and depends on platform and mostly,
it returns “Segmentation Fault (SIGSEGV)” error. To read data from allowed memory
address and desired result, see the following example.

# include < stdio .h >
2 # include < stdlib .h >
42 Basic C

4 int main ( int argc , char ** argv ) {


char x [20] = " This is my string " ;
6 printf ( " Char at address of x is :% c \ n " , * x ) ;
printf ( " Char at address of ( x + 1) is :% c \ n " , *( x + 1) ) ;
8 printf ( " Char at address of ( x + 2) is :% c \ n " , *( x + 2) ) ;
printf ( " Address of x is :% x \ n " , x ) ;
10 /* In my machine , address of x is 0 x22cd40 */
printf ( " Char at address of (0 x22cd40 +0 x1 ) is :% c \ n " , \
12 *( char *) (0 x22cd40 + 0 x1 ) ) ;
return ( EXIT_SUCCESS ) ;
14 }
✆✌

Char at address of x is : T
Char at address of ( x + 1) is : h
Char at address of ( x + 2) is : i
Address of x is :22 ccb 0
Char at address of (0 x 22 cd 40+0 x 1) is : h
✆✌

NULL (\0), a Magic Symbol Let we have a special file which contains our secret
passphrase, keywords including secret passwords. When this file is deleted, only name
variable, that points to the address of the file data, is removed from the file table. Data
stored in permanent memory remains intact. If someone scan the whole memory of the
storage device, he may able to retrieve your secret passphrase or passwords. Then, how
do we make a safe removal of the data file? We can do it my flushing file data with \0
(NULL character) by mapping whole file (using mmap function) in the memory before
its removal. Now, if anyone scan the storage memory, he will get only garbage data.

1 # include < stdio .h >
# include < stdlib .h >
3 # include < sys / mman .h >
# include < fcntl .h >
5

int main ( int argc , char * argv []) {


7 int fd , i ;
char * data ;
9 if (( fd = open ( " a . txt " , O_RDWR ) ) == -1) {
printf ( " Unable to open file .\ n " ) ;
11 return 1;
}
13 /* Put mmap in loop for large size file mapping */
data = mmap (0 , 1024 , PROT_READ | PROT_WRITE , MAP_SHARED , fd , 0) ;
15 if (* data == -1) {
printf ( " Unable to map file .\ n " ) ;
17 return 1;
}
19 for ( i =0; i < 1024; i ++)
data [ i ]= ’ \0 ’; // replace data with garbage
21 return 0;
}
1.3. VARIABLES 43

✆✌
Now open and see the experimental file.

Integers
A 4 bytes long numerical value can be declared and initialized by using int data type. In
following figure, bytes B[3] to B[6] are reserved for storing integer value assigned to the
integer variable i and B[7] to B[10] are reserved for storing integer value assigned to the
integer variable j.

B[2] B[3] B[4] B[5] B[6] B[7] B[8] B[9] B[10] B[11]

xxxx xxxx xxxx xxxx yyyy yyyy yyyy yyyy


i j

When a real number is initialized to a integer variable, then its fraction part is trun-
cated. A valid integer type is either a whole number of a whole number with suffix ‘L’.
An integer variable is declared and initialized as shown below:

int < var name >; /* Declared . */
2 int < var name >= < value >; /* Initialized . */
✆✌
An example is given below:

# include < stdio .h >
2

int main () {
4 int i = 10;
int iL = 11 L ;
6 int j = 12.5;
/* Print whole integer i . */
8 printf ( " i : % d \ n " , i ) ;
/* Print whole integer iL . */
10 printf ( " iL : % d \ n " , iL ) ;
/* Truncated to decimal part of j . */
12 printf ( " j : % d \ n " , j ) ;
return 0;
14 }
✆✌

i : 10
iL : 11
j : 12
✆✌
Similarly, if a double or float number is casted as integer then again its decimal part is
truncated. Remember float number larger than that of size of integer cause overflow.

1 # include < stdio .h >

3 int main () {
44 Basic C

double i = 10.25;
5 float j = 12.75;
printf ( " i : % d \ n " , ( int ) i ) ;
7 printf ( " j : % d \ n " , ( int ) j ) ;
printf ( " j as float : % f \ n " , ( int ) j ) ;
9 return 0;
}
✆✌

i : 10
j : 12
j as float : -0.000000
✆✌
Note that, prepend zeros in the values of integer type variables, cast the values into octal
number form. In C, prepend zeroes has significant meaning here.

1 # include < stdio .h >

3 int main () {
int a = 010; // Declare & assign octal 010 to variable a
5 a = a + 10; // Ouput is a = 10 + 8 = 18 in decimal .
printf ( " % d " , a ) ;
7 return 0;
}
✆✌

18
✆✌
Here, output is decimal 18 and octal 010 is equivalent to decimal 8. Therefore, be cautious
while using prepend zeros in the numeric values.

Integer Casting into Char


Here is a question that how a numerical value is stored as integer and as string and what
is different in these two storing modes. For example, assume a numeric value 62, which
is to be stored as integer and as string. The numeric value 62, as integer, it is equal to
binary value ‘00111110’ and it is stored in the first byte of four byte long storage memory
allocated for integer variable.

1 # include < stdio .h >

3 int main () {
int i = 62; /* Four byte long data type */
5 /* x Point to first byte of address of i */
char * x = ( char *) & i ;
7 printf ( " First byte % d \ n " , x [0]) ;
printf ( " Second byte % d \ n " , x [1]) ;
9 printf ( " Third byte % d \ n " , x [2]) ;
printf ( " Fourth byte % d \ n " , x [3]) ;
11 return 0;
}
✆✌
1.3. VARIABLES 45


First byte 62
Second byte 0
Third byte 0
Fourth byte 0
✆✌
In this case, numeric value is stored as integer needs only one byte (as numeric value is
small) of four bytes allocated memory for integer variable. Remember that, an integer is
four bytes long data.

Value at byte : 0 0 0 62
i: 00000000 00000000 00000000 00111110
Pointer x : x[3] x[2] x[1] x[0]

62 is small number hence it is accommodated in one byte. If this value is larger then
it need two or more bytes to store it. Assume a number 12345. In binary form, it is
“110000 00111001” and accommodated in 4 bytes long memory as shown below:

Value at byte : 0 0 48 57
i: 00000000 00000000 00110000 00111001
Pointer x : x[3] x[2] x[1] x[0]


# include < stdio .h >
2

int main () {
4 int i = 12345; /* Four bytes long */
/* x Point to first byte of address of i */
6 char * x = ( char *) & i ;
printf ( " First byte % d \ n " , x [0]) ;
8 printf ( " Second byte % d \ n " , x [1]) ;
printf ( " Third byte % d \ n " , x [2]) ;
10 printf ( " Fourth byte % d \ n " , x [3]) ;
return 0;
12 }
✆✌

First byte 57
Second byte 48
Third byte 0
Fourth byte 0
✆✌
In image processing, the image data is written byte by byte as group of two, three, four or
more bytes. Four bytes long integers are also written as byte by byte while they are read
as four byte long data. Therefore, pointing to an integer as character by character has
great significance in image processing. Now, in the case, when 62 is stored as a group of
characters, i.e. in form of string, it becomes “62” (a group of character “6” and character
“2”).
46 Basic C


# include < stdio .h >
2

int main () {
4 char * s = " 62 " ; /* Two bytes long */
char * x = s ; /* Points to first byte . */
6 printf ( " First byte : % d = ’% c ’\ n " , x [0] , x [0]) ; /* Char code of 6 */
printf ( " Second byte : % d = ’% c ’\ n " , x [1] , x [1]) ; /* Char code of 2 */
8 return 0;
}
✆✌

First byte : 54= ’6 ’
Second byte : 50= ’2 ’
✆✌
Here, the numeric value 62, is stored as string “62”, it needs two bytes long memory.
One byte for character ‘6’ (char code 54, binary equivalent to 00110110) and one byte for
character ‘2’ (char code 50, binary equivalent to 00110010).

Value at byte : 6 2
s: 00110110 00110010
Pointer x : x[0] x[1]

This is the main difference in storage of integers and strings in computer memory.
Note that the same binary data in a memory byte has different meaning for different data
type. For example, binary value 00110010 is equal to symbol ‘2’ (numeric digit two) for
character data type. The same binary value is equal to number ‘50’ (equal to char code)
for integer data type. Thus each data type has different way of reading and interpreting
binary data.
Little Endian & Big Endian Little and big endian are two ways of storing multibyte
data, i.e. int, float, etc. In little endian machines, least significant byte of binary rep-
resentation of the multibyte data is stored first, i.e. at lowest address of the memory.
In big endian machines, most significant byte of binary representation of the multibyte
data is stored first, i.e. at lowest address of the memory. For example, a multi byte data
12D589A116 is written in the machine as big endian as shown in the following table

Address Value
1000 12
1001 D5
1002 89
1003 A1

The same multibyte data is written in the machine as little endian as shown in the
following table
1.3. VARIABLES 47

Address Value
1000 A1
1001 89
1002 D5
1003 12

The program that can check the machine as little endian or big endian is given below:

# include < stdio .h >
2

int main ( void ) {


4 int * T ;

6 T = ( int *) " \ 0 1 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0" ;


if (* T == 1)
8 printf ( " Machine is High - Endian .\ n " ) ;
else
10 printf ( " Machine is Low - Endian .\ n " ) ;
return 0;
12 }
✆✌
According to this program, my machine is

Machine is High - Endian .
✆✌

Real Numbers
A real number has decimal point. Thus 12.0 and 12 are not equal characteristically but
they are equal numerically. In C, some operators like modulo, left and right shift, etc do
not work with real numbers. In the following example, modulo of 12 by 5 is 2.

1 # include < stdio .h >
# include < stdlib .h >
3

int main ( int argc , char ** argv ) {


5 printf ( " 12 %% 5 = % d \ n " , 12 % 5) ;
return ( EXIT_SUCCESS ) ;
7 }
✆✌

2
✆✌
But in the following example, there is error.

1 # include < stdio .h >
# include < stdlib .h >
3
48 Basic C

int main ( int argc , char ** argv ) {


5 printf ( " 12.0 %% 5 = % d \ n " , 12.0 % 5) ;
return ( EXIT_SUCCESS ) ;
7 }
✆✌
The reason behind these difference is treatment of value 12, i.e. how the bits of memory
bytes stored 12 or 12.0 are grouped, interpreted and converted into numbers. In first
case, it was an integer and all bits in four bytes of integer data type were part of the
integer value. But in above code, 12.0 is a float type values. The bits in four bytes float
data type are treated differently. Few bits are used as mantissa and rest are used for
characteristics. Similarly, left or right bit shift operator do.

1 # include < stdio .h >
# include < stdlib .h >
3

int main ( int argc , char ** argv ) {


5 printf ( " 12.0 << 5 = % d \ n " , 12.0 << 5) ;
return ( EXIT_SUCCESS ) ;
7 }
✆✌
Above code shows error. In left bit shift or right bit shift of real numbers, mentisaa and
characteristics bits trespass each others places. This is why, some operators are illegal
with real numbers.

Float Decimals
This data type is floating-point type. It usually referred to as a single-precision floating-
point. Float-to-integer or integer-to-float type conversion of numbers take place by casting
the number. It is 4 byte long. Its range varies from 1.2×10−38 to 1.2×1038. The precision
of the float data type is upto 6 decimal places. Syntax for the float data type is

1 float < var name >;
float < var name >= < decimal value >;
✆✌
See the example below.

# include < stdio .h >
2

int main () {
4 float i = 10.25;
int j = 15;
6 printf ( " i as float : % f \ n " , i ) ;
printf ( " i as integer : % d \ n " , ( int ) i ) ;
8 printf ( " Int j as float : % f \ n " , ( float ) j ) ;
return 0;
10 }
✆✌

i as float : 10.250000
i as integer : 10
Int j as float : 15.000000
✆✌
1.3. VARIABLES 49

A floating point is represented in scientific notation form by using ‘e’ (here ‘e’ is exponent
and is equivalent to ‘10’) as

1 float 125 e - n
float 125 e + n
✆✌
A positive power ‘+n’ shifts the decimal point from left to right and negative power ‘–
n’ shifts the decimal point from right to left. For example, −12345e + 5 in C notation
is equivalent to −12345 × 10+5 in mathematics. Similarly, 12345e − 5 in C notation is
equivalent to 12345 × 10−5 in mathematics. See the example given below:

# include < stdio .h >
2

int main () {
4 float i = -12345 e +5;
float j = 12345 e -5;
6 printf ( " i is % f \ n " , i ) ;
printf ( " j is % f \ n " , j ) ;
8 return 0;
}
✆✌

i is -1234499968.000000
j is 0.123450
✆✌
A float is 32 bits long and has three components, (i) a sign bit (first bit from left side),
(ii) exponent (next 8 bits from left side) and (iii) mantissa (rest of 23 bits). A floating
point number is written as
f = ±m × b±e
Here, m is mantissa of the number, b is base either ‘10’ or ‘e’ or ‘2’ and n is exponent of
the floating type number. In computers, the base is ‘2’.

Double Decimals
This data type is floating-point type. It usually referred to as a double-precision floating-
point. Double-to-integer or integer-to-double type conversion of numbers take place by
casting of the number. It is 8 bytes long. Its range is from 2.3 × 10−308 to 2.3 × 10308 .
The precision of the double data type is upto 15 decimal places. Syntax for the double
data type is

double < var name >;
2 double < var name >= < decimal value >;
✆✌
See the example below.

# include < stdio .h >
2

int main () {
4 double i = 10.25;
printf ( " i as double : % f \ n " , i ) ;
50 Basic C

6 printf ( " i as integer : % d \ n " , ( int ) i ) ;


return 0;
8 }
✆✌

i as double : 10.250000
i as integer : 10
✆✌
A double is 64 bits long and has three components, (i) a sign bit (first bit from left side),
(ii) exponent (next 11 bits from left side) and (iii) mantissa (rest of 52 bits). A double
point floating point number is written as

f = ±m × b±e

Here, m is mantissa of the number, b is base either ‘10’ or ‘e’ or ‘2’ and n is exponent
of the floating type number. In computers, the base is ‘2’. double data type is preferred
over float in numerical programming to avoid variance and kept precision in results.

# include < stdio .h >
2

int main () {
4 printf ( " % f \ n " , ( float ) 343434333.98) ;
printf ( " % f \ n " , ( float ) 545454323.31) ;
6 printf ( " % f \ n " , ( double ) 343434333.98) ;
printf ( " % f \ n " , ( double ) 545454323.31) ;
8 return 0;
}
✆✌

343434336.0 0 00 00
545454336.0 0 00 00
343434333.9 8 00 00
545454323.3 1 00 00
✆✌

Long Decimals
long is long integer type. It is capable of containing any integer value within the range
from 2147483647 to +2147483647. It is a 32 bits or 4 bytes long in size. Long-to-integer
or integer-to-long type conversion of numbers is done by casting.

long < var name >;
2 long < var name >= < decimal value >;
✆✌
See the example below.

# include < stdio .h >
2

int main () {
4 long i = 10.25;
int j = 15;
1.3. VARIABLES 51

6 printf ( " i as long : % ld \ n " , i ) ;


printf ( " i as integer : % d \ n " , ( int ) i ) ;
8 printf ( " Int j as long : % ld \ n " , ( long ) j ) ;
return 0;
10 }
✆✌

i as long : 10
i as integer : 10
Int j as long : 15
✆✌

Long Double
It is 10 bytes long data type. Its range is from 3.4 × 10−4932 to 3.4 × 104932. The precision
of the long double data type is upto 19 decimal places. Syntax for the long double data
type is

1 long double < var name >;
long double < var name >= < decimal value >;
✆✌
The example is

# include < stdio .h >
2

int main ( void ) {


4 long double x = -5.32 e -5;
printf ( " x = % LE \ n " , x ) ;
6 return 0;
}
✆✌

x = -5.320000 E -05
✆✌

Alias Data type


typedef is used to create an alias name for any other data type. As such, it is often
used to simplify the syntax of declaring complex data structures consisting of struct and
union types, but is just as common in providing specific descriptive type names for integer
datatypes of varying lengths. The syntax of typedef is given by

1 typedef < old type name > < new alias >;
✆✌
Redefining the long long data type with new variable as given below.

1 typedef long long < major unit >;
typedef int < minor unit >;
✆✌
An example is given below.
52 Basic C


# include < stdio .h >
2

typedef long long km ;


4 typedef int mm ;

6 int main ( void ) {


km dis = 10;
8 printf ( " Distance is % d km .\ n " , dis ) ;
return 0;
10 }
✆✌

Distance is 10 km .
✆✌
typedef can also be used to define alias names to a structure. See the example given
below:

1 # include < stdio .h >

3 typedef struct Coord {


int x ;
5 int y ;
} c;
7

int main () {
9 c coord1 = {2 , -5}; // Assign default values
c coord2 = coord1 ; // Copy coord1 into coord2
11 printf ( " % d " , coord2 . y ) ; // get value
return 0;
13 }
✆✌

-5
✆✌
Always remember that, alias names created by using typedef keyword, are used to create
new instances of structure. They do not act as instances themselves. So, accessing the
elements of a structure, as given in above example, like

1 c.x;
c.y;
✆✌
are invalids and give compile time error.

Boolean
C has no dedicated boolean variable. Hence a comparison between variable and return
value can not be performed. In C, the true and false numeric values are depend on the
implementation concepts by the program writer. For example, if two strings are exactly
same, then their comparison by strcmp() function is true and it returns ‘0’. It returns any
number if two strings are not exactly same, i.e. the false case. Similarly, scanf returns
1.3. VARIABLES 53

1 if it success to scan a value according to modifiers otherwise 0 on failure. So, we can


say that boolean returned values are dependent to success or error or failure states or
implementation of user’s function. In following example, we check whether there are
spaces in a string or not.

# include < stdio .h >
2 /* Space function . */
/* Return 0 if no spaces otherwise > 0. */
4 int has_space ( char * s ) {
int num = 0;
6 while (* s ++ != ’ \0 ’ ) {
if (* s == ’ ’) {
8 num ++;
}
10 }
return num ;
12 }

14 int main ( int argc , char ** argv ) {


char * s = " This is pen . " ;
16 printf ( " Spaces : % d \ n " , has_space ( s ) ) ;
return 0;
18 }
✆✌
In concept implementation, function has space() returns the number of space occurring
in the string. It means, if return value is ‘0’ then there are no spaces in the string. Other
positive integer values tells the number of spaces in the string. It means presence of space,
i.e. true state has any positive integer value while false state has ‘0’ value. In following
example, a totally different concept implemented for return value for true or false state.

# include < stdio .h >
2 /* Return 0 if only numeric otherwise > 0. */
int is_only_num e ri c ( char s [ ]) {
4 int num = 0 , i = 0;
while ( s [ i ] != ’ \0 ’ ) {
6 if ( s [ i ] < 48 || s [ i ] > 59) {
num ++;
8 }
i ++;
10 }
return num ;
12 }

14 int main ( int argc , char ** argv ) {


char * s = " 341 " ;
16 printf ( " Numeric only : % d \ n " , is_only_nu me ri c ( s ) ) ;
return 0;
18 }
✆✌
In above function, return value is zero, if string has only numeric digits ranging from 0
to 9. If there are other characters or symbols, the return value is greater than zero. The
54 Basic C

type comparison like



if ( has_space ( s ) == 0)
✆✌
shall be true if there are no spaces in string ‘s’. Again, the type comparison like

1 if ( has_space ( s ) > 0)
✆✌
shall be true if there are spaces in string ‘s’. But

1 if ( has_space ( s ) != 0)
✆✌
can’t be implemented. Boolean in C depends on implementation and varies from library
to library. In mathematics library, true is any number while false is zero.

1 # include < stdio .h >

3 int main () {
int b = 2 , c = 3;
5 printf ( " % d \ n " , ( c > b ) ) ; // true case
printf ( " % d \ n " , ( c < b ) ) ; // false case
7 return 0;
}
✆✌

1
0
✆✌

Declaration, Initialization & Assignment


A variable in C can be assigned as integer, if syntax is defined as given below:

int variable_nam e ;
✆✌
It means there is some space declared somewhere to store integer value. Multiple variables
can be assigned in single line or successive way like

1 int variable_a , variable_b , variable_c ;
✆✌
A variable in C is said to be initialized if a numeric or an alphabetic value is assigned to
it. For example variable a is initialized by

1 int variable_a = < value >;
✆✌
To distinct the words of a variable, underscore symbol (‘ ’) is used. Anytime within a
program in which we specify a value explicitly instead of referring to a variable or some
other form of data, that value is referred as a literal. Literals can either take a form
defined by their type, or one can use hexadecimal (hex) notation to directly insert data
into a variable regardless of its type. Hex numbers are always preceded with ‘0×’. There
1.3. VARIABLES 55

are five major datatypes which are given in the following table. C also allow suitable
combinations of numeric datatypes for long numerical values.

Data type Meaning


int Integer
char Character
long Long integer
float Floating data with single digit precision
double Floating data with double digit precision

The length of data type is measured its byte length. The data type may be signed or
unsigned. In signed data type, the MSB is used for sign declaration and rest of the bits
are used for data value. In unsigned data type, all the bits are used for data value. The
byte length of different data type are given in following table.

Type Storage size Format Specifier


char 1 byte %c
un-signed char 1 byte %c (%hhu for numerical output)
signed char 1 byte %c (%hhi for numerical output)
int 2 or 4 bytes %i or %d
unsigned int 2 or 4 bytes %u
unsigned short 2 bytes %hu
short 2 bytes %hi
long 4 bytes %li
unsigned long 4 bytes %lu
long long 8 bytes %lli
long long int 8 bytes %lli or %Ld
unsigned long long 8 bytes %llu
double 8 bytes %f
long double 10 bytes %Lf

Table 1.10: Declaration type and their storage size in byte.

Example, that scans a 8 bytes long integer by using ‘%Ld’ format specifier.

1 # include < stdio .h >
56 Basic C

3 int main () {
long long int a ;
5 scanf ( " % Ld " ,& a ) ;
if ( a %6==0 || a %6==1 || a %6==3) {
7 printf ( " YES " ) ;
} else {
9 printf ( " NO " ) ;
}
11 return 0;
}
✆✌

2154478958845
YES
✆✌
Example for long double data type.

# include < stdio .h >
2 # include < math .h >

4 int main () {
long double x ;
6 printf ( " % lf \ n " , pow (2 ,50) ) ;
return 0;
8 }
✆✌

1125899906842624.000000
✆✌
Sometime, variables are declared but not initialized and further used. Integer type data
variables if declared as static or global, they store zero by default.

1 # include < stdio .h >

3 int main () {
int i ;
5 printf ( " % d \ n " , i ) ;
return 0;
7 }
✆✌

0
✆✌
Though, the non-initialized integers are zero by default, yet the initialization of integer
variables are required. If not initialized, the result is garbage.

1 # include < stdio .h >

3 int main () {
int i ;
5 int j ;
while ( i < 5) {
1.3. VARIABLES 57

7 j = i + j;
i ++;
9 }
printf ( " i :% d , j :% d \ n " , i , j ) ;
11 return 0;
}
✆✌

i :5 , j : -1081549298
✆✌
The same problem gives desired result if a printf function is placed inside while loop.

1 # include < stdio .h >

3 int main () {
int i ;
5 int j ;
while ( i < 5) {
7 j = i + j;
printf ( " i :% d , j :% d \ n " , i , j ) ;
9 i ++;
}
11 printf ( " i :% d , j :% d \ n " , i , j ) ;
return 0;
13 }
✆✌

% Inner loop printf %
i :0 , j :0
i :1 , j :1
i :2 , j :3
i :3 , j :6
i :4 , j :10
% Outer loop printf %
i :5 , j :10
✆✌
In the following example, ‘res’ variable is not initialized. Hence the result is not as we
required.

# include < stdio .h >
2

int main () {
4 char intg [ ] = " 1234233 " ;
/* res is not initialised and assumed as zero */
6 int i = 0 , res ;
while ( intg [ i ] != ’ \0 ’) {
8 /* Product of res with 10 is null . */
res = res * 10 + ( intg [ i ] % 48) ;
10 i ++;
}
12 printf ( " % d \ n " , res ) ;
return 0;
58 Basic C

14 }
✆✌

-678766791
✆✌
But when res in above example is initialized then answer is that as we required.

1 # include < stdio .h >

3 int main () {
char intg [ ] = " 1234233 " ;
5 /* Res is not initialised to 0. */
int i = 0 , res =0;
7 while ( intg [ i ] != ’ \0 ’) {
/* Product of res with 10 is null . */
9 res = res * 10 + ( intg [ i ] % 48) ;
i ++;
11 }
printf ( " % d \ n " , res ) ;
13 return 0;
}
✆✌

1234233
✆✌
Observing above examples given for un-initialized variables, it is recommended that each
variable should be initialized before its use to avoid unpredictable results. See the follow-
ing example, in which variable ‘i’ is not initialized inside the XYZ() function. i.e.

1 int i ;
✆✌
The while function does not give any output.

1 # include < stdio .h >

3 int XYZ () {
int i ; /* i is NOT initialized . */
5 int loops = 5;
while ( i < loops ) {
7 /* It shall NOT be printed at output console . */
printf ( " i is % d \ n " , i ) ;
9 i ++;
}
11 return 0;
}
13

int main ( void ) {


15 /* Call XYZ () function . */
XYZ () ;
17 return 0;
}
✆✌
1.3. VARIABLES 59

When we initialized the variable ‘i’ inside the XYZ() function as given below.

int i =0;
✆✌
The while function gives desired output.

1 # include < stdio .h >

3 int XYZ () {
int i =0; /* i is initialized . */
5 int loops = 5;
while ( i < loops ) {
7 /* It shall be printed at output console . */
printf ( " i is % d \ n " , i ) ;
9 i ++;
}
11 return 0;
}
13

int main ( void ) {


15 /* Call XYZ () function . */
XYZ () ;
17 return 0;
}
✆✌

i is 0
i is 1
i is 2
i is 3
i is 4
✆✌
In the C language’s grammar, a scalar initializer may be enclosed in any number of curly
brace pairs.

1 int x = 12;
int y = { 23 }; // valid , no warning
✆✌
Most compilers issue a warning if there is more than one such pair.

int z = { { 34 } }; // valid , expects a warning
✆✌
If there are multiple values being assigned to a variable and are comma separated then
assignment of value to the variable is take place in Right-to-Left order. For example

1 int i =10 , 20 , 30; // valid
✆✌
always assigns value 10 to i. Structures, unions and arrays stores data of variable numbers
and size. These can be initialized in their declaration using an initializer list. Without
designator, the initialization of a structure, union or array is sequential. To initialize a
successive element, the preceding element must be initialized by assigning a value either
empty, null or zero. For example, take the structure as
60 Basic C


1 struct st {
int x ;
3 float y ;
char * z ;
5 };
✆✌
To initialize z without designation, initializer list is used like

1 /* Following type of declaration is invalid *
* as its first element must be an integer */
3 struct st k = { " Konark Temple " };
/* Following declaration is invalid and *
5 * unacceptable . Its first and second *
* elements must be an integer or a float */
7 struct st k = {4 , " Konark Temple " };
/* Following declarations are valid */
9 struct st k = {3 , 4 , " Konark Temple " };
struct st k = {0 , 0 , " Konark Temple " };
✆✌
Here is the complete example in which struct table is initialized with integers and strings.

# include < stdio .h >
2 # include < stdlib .h >

4 struct st {
int x ;
6 float y ;
char * z ;
8 };

10 int main ( void ) {


struct st k = { " Konark Temple " }; /* Illegal assignment */
12 printf ( " Temple name is % s \ n " , k . z ) ;
return EXIT_SUCCESS ;
14 }
✆✌

Temple name is null
✆✌
The above example is modified for different output.

1 # include < stdio .h >
# include < stdlib .h >
3

struct st {
5 int x ;
float y ;
7 char * z ;
};
9

int main ( void ) {


1.3. VARIABLES 61

11 /* valid assignment */
struct st k = {0 , 0 , " Konark Temple " };
13 printf ( " % d \ n " , k . x ) ;
printf ( " Temple name is % s \ n " , k . z ) ;
15 return EXIT_SUCCESS ;
}
✆✌

0
Temple name is Konark Temple
✆✌
To overcome this strict initialization, designated initializers are used like

/* valid and acceptable */
2 struct st k = {. z = " Konark Temple " };
✆✌

# include < stdio .h >
2 # include < stdlib .h >

4 struct st {
int x ;
6 float y ;
char * z ;
8 };

10 int main ( void ) {


// valid designator initializer
12 struct st k = {. z = " Konark Temple " };
printf ( " Temple name is % s \ n " , k . z ) ;
14 return EXIT_SUCCESS ;
}
✆✌

Temple name is Konark Temple
✆✌
Designated initializers allow its members to be initialized by name, in any order, and
without explicitly providing the preceding values. Compound designators can be used to
provide explicit initialization.

1 struct { int a [3] , b ; } w [ ] =
{
3 { { 1, 0, 0 }, 0 },
{ { 2, 0, 0 }, 0 }
5 };
✆✌
Compound literals are often combined with designated initializers to make the declaration
more readable:

1 pi = ( struct s ) { . z = " Pi " , . x = 3 , . y = 3.1415 };
✆✌
62 Basic C


1 # include < stdio .h >
# include < stdlib .h >
3

struct st {
5 int x ;
float y ;
7 char * z ;
};
9

int main ( void ) {


11 struct st k ;
k = ( struct st ) { . z = " Konark Temple " , . x = 1 , . y = 1.51 };
13 printf ( " Temple name is % s \ n " , k . z ) ;
return EXIT_SUCCESS ;
15 }
✆✌

Temple name is Konark Temple
✆✌
By default, strings are addresses of memory where strings are stored. Integer variables
are not so. This is why to get the address of integer value, integer variables are prefixed
with ‘&’ symbol.

1 int i =10;

3 /* It is address of integer i *
* where value 10 is stored . */
5 int * j =& i ;

7 char j [10]= " Harappa " ; /* j is address itself . */


✆✌
See the following example, which is complete code of the above code snippet.

1 # include < stdio .h >

3 int print ( int * i ) {


printf ( " % d " , * i ) ;
5 return 0;
}
7

int main () {
9 int i = 10;
int * j = & i ;
11 print ( j ) ;
return 0;
13 }
✆✌

10
✆✌
1.3. VARIABLES 63

Float To Integer
Variable type ‘int’ stores data with zero digit precision while ‘float’ stores data with single
digit precision. When a floating point number is assigned to an integer type variable then
only whole part of the floating point number is assigned to the integer variable, and its
fraction part is truncated. See the example below.

1 # include < stdio .h >

3 int main () {
float x ;
5 printf ( " Enter a number : " ) ;
scanf ( " % f " , & x ) ;
7 int y = x ;
float z = ( x - y ) ;
9 printf ( " Whole part is % d \ n " , y ) ;
printf ( " Fraction part is % f \ n " , z ) ;
11 return 0;
}
✆✌
The output of this program is

Enter a number : 2.5
Whole part is 2
Fraction part is 0.500000
✆✌

Signed & Unsigned Integer


A byte is 8 bits long memory space. The size of int is 4 byte, i.e. 32 bits. In a signed
integer, first bit, from MSB side is considered as sign bit and remaining 31 bits are used
for storing of an integer value. If integer is defined as unsigned then all 32 bits are used
for storing of an integer value. For convenience of understanding, assume that we are
storing small integer type value, and it is one byte long as shown below:

Sign bit

1 1 1 1 1 1 1 1

1 Byte

As the above byte is signed integer byte, hence its MSB bit represents to sign of the
integer. Bit 1 represents to negative sign and bit 0 represents to positive sign. This is
why, above binary data is equivalent to -127 decimal value.

Sign bit

0 1 1 1 1 1 1 1

1 Byte
64 Basic C

As the above byte is signed integer byte, hence its MSB bit represents to sign of the
integer. Bit 1 represents to negative sign and bit 0 represents to positive sign. This is
why, above binary data is equivalent to -127 decimal value.

1 // + - - - - - - - - - - - - - - - - - - - - - Sign bit
(1) 1111111 b = > -127 d // Signed 8 bits long integer
3 11111111 b = > 255 d // Unsigned 8 bits long integer
✆✌

1 1 1 1 1 1 1 1

1 Byte

As the above byte is unsigned integer byte. This is why, above binary data is equivalent
to 255 decimal value. A signed integer ranges from -2147483647 to 2147483647 while
unsigned integer ranges from 0 to 4294967294. In the C, bit ‘0’ is used for positive sign
and bit ‘1’ is used for negative sign. Now, a question is here that what will happen if we
store a negative number to the unsigned variable? For example,

1 unsigned char i = -16; // char type for one byte long data
✆✌
The answer is that, here, compiler uses one’s complement method to store the negative
value. It means first, 16 is converted into binary data and then it is complemented and
added by bit 1. The result thus obtained is stored in the memory address pointed by the
variable.

0 0 0 1 0 0 0 0 = 1610

1 Byte

1 1 1 0 1 1 1 1 = 23910
Complement
1 Byte

1 1 1 1 0 0 0 0 = 24010
Complement + 1
1 Byte
Now, an unsigned variable (one byte long here) stores value -16 in memory as binary
11110000b. See the example given below:

1 # include < stdio .h >

3 int main () {
unsigned char c = -16;
5 printf ( " % d \ n " , c ) ;
return 0;
7 }
✆✌
1.3. VARIABLES 65


240
✆✌

Overflow of Data
A variable declared as integer, long, float or double integer and character has capacity
to store a specific size of data. An integer variable can not store data as long as float
variable. This is why, a variable shall be declared of proper size for storing a data. To
understand the overflow, consider a variable ‘k’ of virtual data type, DATATYPE, that
can store only one byte long data. This variable ‘k’ may be signed or unsigned. First
assume it is unsigned, then the largest decimal value, that can be stored by it is 255.
Initially, ‘k’ is declared and initialized with decimal value 254.

1 DATATYPE k ;
k = 254 d = 11111110 b ; /* 8 bit result */
✆✌
Here, suffix ‘d’ represents the decimal form of number and ‘b’ represents to binary form
of number. Now, ‘k’ is incremented by 1, it becomes

k = 255 d = 11111111 b ; /* 8 bit result */
✆✌
Again, ‘k’ is incremented by 1, it becomes

1 k = 256 d = 1 00000000 b ; /* 9 bit result */
✆✌
The bit size of result is larger than one byte. The value of ‘k’ is reset to zero due to
overflow. Here, overflow carry is ‘1’. Similarly a positive signed value becomes negative
signed value if it is incremented beyond the signed data range. Taking the same data
type DATATYPE, and variable ‘k’ with signed value.

1 /* Bit inside parentheses represents to sign . */
signed DATATYPE k ;
3 k = 127 d = (0) 1111111 b ;
✆✌
Here, suffix ‘d’ represents the decimal form of number and ‘b’ represents to binary form
of number. Now, ‘k’ is incremented by 1, the result becomes

1 /* Bit inside parentheses represents to sign . */
k = -0 d = (1) 0000000 b ;
✆✌
It becomes negative zero. Again, if ‘k’ is incremented by 1, the result becomes

/* Bit inside parentheses represents to sign . */
2 k = -1 d = (1) 0000001 b ;
✆✌
Which is -1. Here, again ‘k’ is overflowed.
66 Basic C

k th Byte

0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1

+ 1

0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0

lth Byte k th Byte

Maximum size of one byte long data is decimal 255. When it is binary added by bit
1. The result becomes 256. The bit arrangement of result 256 is shown in above figure.
Additive carry bit 1, is stored in another byte while actual byte has all 0 bits. One byte
long data type variable (say ‘i’) that points to this byte takes additive carry bit as overflow
bit and it is un-used for this variable. Therefore, the value of variable ‘i’ becomes zero.

# include < stdio .h >
2

int main () {
4 int i ; /* Four bytes long */
unsigned char * x ; /* One byte long */
6 for ( i = 255; i <= 256; i ++) {
/* Points to each byte independentl y of integer i . */
8 x = ( char *) & i ;
/* Print little endian byte only of integer i . */
10 printf ( " x [0] byte of integer % d is % d \ n " , i , x [0]) ;
}
12 return 0;
}
✆✌
Little endian byte access by variable ‘x’ of above example is illustrated in the following
figure.
x[0] Byte

0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1

+ 1

0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0

x[0] Byte

Output of above example is shown below:



x [0] byte of integer 255 is 255
x [0] byte of integer 256 is 0
✆✌
See another example given below, in which result is not as required due to bigger size
of data as the integer variable can store. An integer can store 2 or 4 byte long data. In
1.3. VARIABLES 67

numerical equivalent the maximum unsigned number can be stored by an integer variable
is ‘2147483647’. If number is larger than it, the result is wiered.

# include < stdio .h >
2 # include < stdlib .h >

4 int main ( void ) {


/* Signed value of an integer ranges *
6 * from -2147483648 to 2147483647. If *
* integer value become larger than *
8 * 2147483647 it overflows by one bit *
* and integer value becomes largest *
10 * negative number . */
signed int i = 2147483645;
12 int j ;
for ( j = 0; j < 5; j ++)
14 printf ( " % d \ n " , i + j ) ;
return EXIT_SUCCESS ;
16 }
✆✌

2147483645
2147483646
2147483647
-2147483648
-2147483647
✆✌
The unsigned integers were standard in ISO C90. In later C standards, an integer is
implicitly is a signed integer. Following example will give a strange result though the
integer value is less than the largest unsigned integer value.

1 # include < stdio .h >
# include < stdlib .h >
3

int main ( void ) {


5 /* Unsigned value of an integer *
* ranges from 0 to 4294967295. */
7 signed int i = 4294967293;
int j ;
9 for ( j = 0; j < 5; j ++)
printf ( " % d \ n " , i + j ) ;
11 return EXIT_SUCCESS ;
}
✆✌

-3
-2
-1
0
1
✆✌
68 Basic C

So, the double data type is used in place of unsigned int to used integers larger than
2147483647.

1 # include < stdio .h >
# include < stdlib .h >
3

int main ( void ) {


5 /* Unsigned value of an integer *
* ranges from 0 to 4294967295. */
7 double i = 4294967293.0 0;
double j ;
9 for ( j = 0; j < 5; j ++)
printf ( " % f \ n " , i + j ) ;
11 return EXIT_SUCCESS ;
}
✆✌

4294967293 .0 0 00 00
4294967294 .0 0 00 00
4294967295 .0 0 00 00
4294967296 .0 0 00 00
4294967297 .0 0 00 00
✆✌
Following is another good example.

1 # include < stdio .h >

3 int Fac ( int i ) {


int j = 1;
5 while ( i > 0) {
j = j*i;
7 i - -;
}
9 return j ;
}
11

int main () {
13 int i = 10;
while ( i < 15) {
15 printf ( " Factorial of % d is % d \ n " , i , Fac ( i ) ) ;
i ++;
17 }
return 0;
19 }
✆✌
The output of the program is

Factorial of 10 is 3628800
Factorial of 11 is 39916800
Factorial of 12 is 479001600
% Actual Factorial of 13 is 6227020800
Factorial of 13 is 1932053504 % Wiered result
1.3. VARIABLES 69

% Actual Factorial of 14 is 87178291200


Factorial of 14 is 1278945280 % Wiered result
✆✌

Memory Size (sizeof )


sizeof () function is used to find the memory used by a variable, pointer, array or structure.
Its result is used in implementation process. The return value of this function is either
unsigned long or unsigned int. In the following example, memory spaced allocated or
to be allocated for pointer-to-integer variables or pointer-to-arrays is obtained by using
sizeof ().

1 # include < stdio .h >
# include < limits .h >
3

int main ( void ) {


5 int * a ; /* Single pointer - to - integer variable */
printf ( " Storage size for a : % d \ n " , sizeof ( a ) ) ;
7 int * b [10]; /* pointer - to - integer array with 10 elements */
printf ( " Storage size for b : % d \ n " , sizeof ( b ) ) ;
9 int * c [20]; /* pointer - to - integer array with 20 elements */
printf ( " Storage size for c : % d \ n " , sizeof ( c ) ) ;
11 int * d [30]; /* pointer - to - integer array with 30 elements */
printf ( " Storage size for d : % d \ n " , sizeof ( d ) ) ;
13 return 0;
}
✆✌
The output is

Storage size of a : 4
Storage size of b : 40
Storage size of c : 80
Storage size of d : 120
✆✌
When sizeof is used to get the size of an array it returns one more than the actual
size of array (size is sum of number of array elements and following null terminating
character). It always returns size of first associated element if its argument is dereference
to a pointer variable.

# include < stdio .h >
2 # include < stdlib .h >

4 /* arr [ ] points to the string , Hello . */


const char arr [ ] = " Hello " ;
6 /* * cp points to the address of char , H */
const char * cp = " Hello " ;
8

int main () {
10 /* Returns size of whole string including terminating char . */
printf ( " Size of array % lu \ n " , ( unsigned long ) sizeof ( arr ) ) ;
12 /* Returns size of first character of string . It is char size . */
70 Basic C

printf ( " Size of * cp % lu \ n " , ( unsigned long ) sizeof (* cp ) ) ;


14 exit ( EXIT_SUCCESS ) ;
}
✆✌

Size of array 6
Size of * cp 1
✆✌
Similarly for integer pointers

# include < stdio .h >
2

/* * cp points to the address of integer */


4 const int * cp = {10};

6 int main () {
/* Returns size of first element of integer array . */
8 printf ( " Size of * cp % lu \ n " , ( unsigned long ) sizeof (* cp ) ) ;
return 0;
10 }
✆✌

Size of * cp 4
✆✌
Similarly, memory space used by an integer array can also be obtained. Remember that,
size of a pointer is fixed for a compiler. All pointer types take same number of bytes for a
compiler. That is why, we get the size of pointer ‘pi’ and ‘pc’ as 4 bytes in the following
example.

1 # include < stdio .h >

3 int main () {
/* Array of integers . */
5 int i [ ] = {1 , 2 , 3};
/* Point to address of first integer element .*
7 * Here pi is pointer to the integer array i . */
int * pi = i ; /* Size of pointer is fixed */
9

/* Array of characters . */
11 char c [ ] = {1 , 2 , 3};
/* Point to address of first character element .*
13 * Here pc is pointer to the character array c . */
char * pc = c ; /* Size of pointer is fixed */
15

printf ( " Size of i [ ] = % d \ n " , sizeof ( i ) ) ;


17 printf ( " Size of pi = % d \ n \ n " , sizeof ( pi ) ) ;

19 printf ( " Size of c [ ] = % d \ n " , sizeof ( c ) ) ;


printf ( " Size of pc = % d \ n " , sizeof ( pc ) ) ;
21

return 0;
23 }
✆✌
1.3. VARIABLES 71


Size of i [ ] = 12
Size of pi = 4

Size of c [ ] = 3
Size of pc = 4
✆✌
The safe way to use sizeof operator is; either cast the return value to unsigned long or to
use the defined type size t provided in the ‘stddef.h’ header file.

1 # include < stddef .h >
# include < stdio .h >
3 # include < stdlib .h >

5 main () {
size_t sz ;
7 sz = sizeof ( sz ) ;
printf ( " Size of sizeof is % lu \ n " ,
9 ( unsigned long ) sz ) ;
exit ( EXIT_SUCCESS ) ;
11 }
✆✌

Size of sizeof is 4
✆✌
Here is another example.

1 # include < stdio .h >
# include < stdlib .h >
3 const char * list [ ] = { " Red " , " Green " , " Blue " , " Black " , " White " };
# define LIST_SIZE ( sizeof ( list ) / sizeof ( list [0]) )
5

int main ( int argc , char * argv [ ]) {


7 int ix ;
for ( ix = 0; ix < LIST_SIZE ; ix ++) {
9 printf ( " % s \ n " , list [ ix ]) ;
}
11 return 0;
}
✆✌

Red
Green
Blue
Black
White
✆✌
A function, equivalent to sizeof() function is explained in following example.

1 # include < stdio .h >

3 int main () {
72 Basic C

/* Pointer ’s name . */
5 char * ptA , * ptB ;
char fl ;
7 /* Get initial pointer location for character */
ptA = & fl ;
9 /* Get next pointer location for character . *
* Addition of 1 in pointer , pointer jumps *
11 * equivalent to the zide of data type . */
ptB = (& fl + 1) ;
13 /* Size of character . */
printf ( " Size of char is % u " , ptB - ptA ) ;
15 return 0;
}
✆✌

Size of char is 4
✆✌
In case of numerical array, the argument of sizeof () function may be first element value
itself of its data type. Both gives same result.

1 # include < stdio .h >

3 int main ( int argc , char * argv [ ]) {


float A [ ] = {10.10 , 50.50 , 4.57 , 1.21};
5 float B [ ] = {10.10 , 50.50 , 4.57 , 1.21 , 2.21};
printf ( " Elements in array A are : %d\n",
sizeof ( A ) / sizeof ( float ) ) ;
7 printf ( " Elements in array A are : %d\n",
sizeof ( A ) / sizeof ( A [0]) ) ;
printf ( " Elements in array B are : %d\n",
sizeof ( B ) / sizeof ( float ) ) ;
9 printf ( " Elements in array B are : %d\n",
sizeof ( B ) / sizeof ( B [0]) ) ;
return 0;
11 }
✆✌

Elements in array A are : 4
Elements in array A are : 4
Elements in array B are : 5
Elements in array B are : 5
✆✌

Casting
We knew that, a data type arranges memory bytes to be read or write at once. For
example, the character data type read and write one character in one byte at once.
Integer data type uses four bytes at once to read or write one integer value, and so on.
Casting is performed to convert a value of one data type into other form of data type.
For example, conversion of integer data type into float or double data type, or conversion
1.3. VARIABLES 73

of integer data type into character data type. Actually, casting rearranges the number of
bytes being read or write by a variable.

char c=(char) i;

i: 0×00 0×00 0×00 0×04 c: 0×00 0×00 0×00 0×04

In above figure, an integer ‘i’ is casted into character data type, i.e. data which was
represented by group of four bytes is now arranged into data represented by group of one
byte. Now, the character data type ‘c’ points to array of four bytes. In casting only way
of grouping of bytes changes, while the number of bytes remain same. In C, there are
two types of castings, (i) implicit casting and (ii) explicit casting. Implicit type casting is
automatically handled by compiler i.e. when two or more datatypes are under execution.
The final data-type will be that data type which is declared.

// integer data type variable declared & initialized
2 int i = 2;
// double data type variable declared & initialized
4 double j = 2;
// integer i is casted as double and used
6 double k = j / i ;
✆✌
An explicit type cast is a cast that should we specifically invoked with either of the cast.
The compiler does not automatically invoke to resolve the data type conversion.

// integer data type variable declared & initialized
2 int i = 2;
double j = i ; // implicit casting
4 double k = ( double ) i ; // explicit casting or forced casting
✆✌
In casting, data of one data type is converted into data of other data type. Therefore,
there is loss of data. Loss of data is due to way and length of reading data stored in the
memory. The same binary data of memory bytes are read in different way for character
data type or integer data type or in float data type. For example, if double data type is
casted as integer data type, then compiler shows warning.

// double data type variable declared & initialized
2 double i = 2.0;
int j = i ; /* warning !! as double (8 bytes size ) *
4 * is casted to integer (4 bytes size ) . *
* Possible loss of data */
✆✌
In case of referencing, implicit casting results warning, while explicit casting is acceptable
without warning.

1 // integer data type variable declared & initialized
int i = 2;
3 // double data type variable declared & initialized
double j = 2.5;
74 Basic C

5 double * k = & j ; // explicit casting or forced casting


i = k ; // warning !! assignment makes integer from
7 // pointer without a cast
i = ( int ) k ; // explicit casting , acceptable
✆✌
See an example for casting that is given below:

# include < stdio .h >
2

void main () {
4 /* Integer type values . */
int m1 = 70 , m2 = 70 , m3 = 100 , total ;
6 /* ’ per ’ variable is float type . */
float per ;
8 /* Total is integer type . */
total = m1 + m2 + m3 ;
10 /* Result ’ per ’ variable is of integer type .*
* as all the variables are integer type . */
12 per = total / 300 * 100;
/* ’ per ’ are called as float while *
14 * all the variables are integer type . */
printf ( " The perc is % f " , per ) ;
16 printf ( " \ n " ) ;
/* Result ’ per ’ variable is integer type . *
18 * ’ total ’ is cast as float . So that result *
* via ’ per ’ variable convert to float type . */
20 per = ( float ) total / 300 * 100; // Explicit casting
/* ’ per ’ are called as float . */
22 printf ( " The perc is % f " , per ) ;
printf ( " \ n " ) ;
24 }
✆✌
Output of above program is

The perc is 0.000000
The perc is 80.000000
✆✌
The casting data type is always put inside the parentheses otherwise compiler tries to
re-declare existing variable again and shows compile time error.

Scope of Variables
A variable has either global or local scope. A variable declared at the header of program
has global access restrict to the code file. A variable declared inside a function has scoped
only within the function. A variable declared within braced block has scope within the
block only.

# include < stdio .h >
2 int i = 0; /* Global scope of variable . */

4 int main () {
1.3. VARIABLES 75

int j = 10; /* Local scope within main () */


6 { /* Start of new block 1 */
int j = 20; /* Local scope within block 1 */
8 printf ( " j inside block 1 is % d \ n " , j ) ;
{ /* Start of new block 2 */
10 int j = 30; /* Local scope within block 2 */
printf ( " j inside block 2 is % d \ n " , j ) ;
12 } /* End of the block 2 */
printf ( " j inside block 1 is % d \ n " , j ) ; /* j =2 */
14 } /* End of the block 1 */
printf ( " j within main () is % d \ n " , j ) ;
16 printf ( " i within main () is % d \ n " , i ) ;
printf ( " Updated j within main () is % d \ n " , ++ j ) ;
18 printf ( " Updated i within main () is % d \ n " , ++ i ) ;
/* Try to update value of i . Compile error *
20 * as i has local scope within braced block */
// i = 3;
22 // printf (" Updated i is % d \ n " , i ) ;
return 0;
24 }
✆✌

j inside block 1 is 20
j inside block 2 is 30
j inside block 1 is 20
j within main () is 10
i within main () is 0
Updated j within main () is 11
Updated i within main () is 1
✆✌
A variable declared as extern qualifier has global access to whole program. Using extern
qualifiers we can access the variables declared in other code files of a program.

1.3.2 Qualifiers
Qualifiers are those keywords which are used to restrict the nature of a variable. A
variable declared as const type can not be updated later. Similarly, a variable declared
as extern can access to variable declared in other code files within the program.

const Qualifier
When the const qualifier is used, the declared variable must be initialized at declaration.
It is then not allowed to be changed. const declaration creates the declared variable as
read only. The method of const declaration is

1 const int i = 12; // OK
✆✌
The constant variable must be defined when they are declared as shown above. Therefore,
it is not allowed to declare const variable as given below.
76 Basic C


1 const int i ;
i =12; // Not OK
✆✌
An array can also be declared const that can not be altered later. For example

const int mdays [12] = {31 ,28 ,31 ,30 ,31 ,30 ,31 ,31 ,30 ,31 ,30 ,31};
✆✌
A pointer can also be declared as constant.

1 const float * ptrf ; /* ptrf points to a constant float value */
✆✌
In following example, i is declared as constant integer equal to 10. It is printed int the
output console.

1 # include < stdio .h >

3 int main ( int argc , char * argv [ ]) {


/* Declare i as constant integer .*
5 * And initialize it at here . */
const int i = 10;
7 printf ( " i is % d \ n " , i ) ;
return 0;
9 }
✆✌

i is 10
✆✌
But changing the value of variable i is not allowed. In following example, compiler shows
error at i++;

1 # include < stdio .h >

3 int main ( int argc , char * argv [ ]) {


/* Declare i as constant integer .*
5 * And initialize it at here . */
const int i = 10;
7 printf ( " i is % d \ n " , i ) ;
/* Increment of i is not allowed . */
9 i ++; /* Illegar expression . Will show error . */
printf ( " i ++ is % d \ n " , i ) ;
11 return 0;
}
✆✌
The const type variable can not be assigned new values. But value can be changed by
other code or pointer.

# include < stdio .h >
2 # include < stdlib .h >

4 int main () {
const volatile int i = 10;
1.3. VARIABLES 77

6 printf ( " i is % d \ n " , i ) ;


int * mod = ( int *) & i ;
8 * mod = 20;
printf ( " Now , i is % d \ n " , i ) ;
10 return ( EXIT_SUCCESS ) ;
}
✆✌

i is 10
Now , i is 20
✆✌
A structure is declared as const type and may or may not initialized. Further, the data
members of the instances can not be modified later. If we try to modify them, a compile
time error (‘assignment to read-only type variable’) is shown by the compiler. See the
example below:

# include < stdio .h >
2 # include < stdlib .h >

4 struct myS {
int i ;
6 int j ;
};
8

int main ( void ) {


10 /* struct instances s is declared & *
* assigned values to its members */
12 struct myS s = {9 , 19};
printf ( " s : %d , % d \ n " , s .i , s . j ) ;
14 /* Update member values of s */
s . i = 10;
16 s . j = 20;
printf ( " s : %d , % d \ n " , s .i , s . j ) ;
18 /* struct instances t is declared here as const *
* and it is initialized with initial values . */
20 const struct myS t = {15 , 25};
printf ( " t : %d , % d \ n " , t .i , t . j ) ;
22 /* Update member values of const type t *
* It returns errors at compile time . */
24 // t . i = 16;// Uncomment line to see the error
return 0;
26 }
✆✌

s : 9 , 19
s : 10 , 20
t : 15 , 25
✆✌
78 Basic C

static Qualifier
When we declare a function or global variable as static it becomes internal. We cannot
access the function or variable through the extern keyword from other files. When we
declare a local variable as static, it is created just like any other variable. However, when
the variable goes out of scope the variable stays in memory, retaining its value, until the
program ends. Variables declared static are initialized to zero (or for pointers, NULL) by
default.

1 # include < stdio .h >

3 /* This variable is accessed by both up () and down () functions . */


static int j = 0;
5

void up ( void ) {
7 /* k is set to 0 when the program starts . The line *
* is then " ignored " for the rest of the program . *
9 *( k is not set to 0 every time up () is called ) */
static int k = 0;
11 j ++;
k ++;
13 printf ( " up () called . k = %2 d , j = %2 d \ n " , k , j ) ;
}
15

void down ( void ) {


17 static int k = 0;
j - -;
19 k - -;
printf ( " down () called . k = %2 d , j = %2 d \ n " , k , j ) ;
21 }

23 int main ( void ) {


int i ;
25 /* Call the up function 3 times , then the down function 2 times */
for ( i = 0; i < 3; i ++)
27 up () ;
for ( i = 0; i < 2; i ++)
29 down () ;
return 0;
31 }
✆✌
Output of above function is

up () called . k =1 , j =1
up () called . k =2 , j =2
up () called . k =3 , j =3
down () called . k = -1 , j =2
down () called . k = -2 , j =1
✆✌
The ‘j’ variable is accessible by both up and down and retains its value. The ‘k’
variables also retain their value, but they are two different variables, one in each of their
scopes. Static variables are a good way to implement encapsulation.
1.3. VARIABLES 79

Property Default Value


Keyword used static
Storage Memory
Default value Zero
Scope Local to the block in which it is declared
Life Time Value persists between different function calls
Optionality Mandatory to use the keyword

Table 1.11: Features of static variable.

When a variable is declared as static, it is assigned value ‘0’ automatically.



1 # include < stdio .h >

3 int main () {
static int i ;
5 int j ;
printf ( " % d \ n " , i ) ; // prints 0
7 printf ( " % d \ n " , j ) ; // j acts as wild pointer , prints garbage
return 0;
9 }
✆✌

0
1629773328
✆✌
Static variable initialized once can not be re-initialized, but the variable can store new
value.

# include < stdio .h >
2 # include < stdlib .h >

4 void print ( void ) {


/* Static initializati on of a */
6 static int a = 0;
/* Print value of a */
8 printf ( " % d \ n " , a ) ;
/* Increment of the static value */
10 a ++;
}
12

int main ( void ) {


14 print () ; // a is initialized in this function call
print () ; // a is NOT reinitialized but stores a +1 value
16 print () ; // a is NOT reinitialized but stores a +2 value
return 0;
18 }
✆✌
80 Basic C


0
1
2
✆✌
C does not advocate to return the address of a local variable to outside of the function.
Hence it is recommended that the local variable should be defined as static variable. Take
and example as given below:

1 # include < stdio .h >
int * myF ( ) {
3 int r [1];
r [0]=10;
5 return r ;
}
7 int main () {
int * p ;
9 p = muF () ;
printf ( " % d \ n " , * p ) ;
11 return 0;
}
✆✌
On compilation of above program, the result shall be shown correctly but the compiler
shall warn about that the function returns address of local variable. Output of above
example is looked like

warning : function returns address of local variable
[ - Wreturn - local - addr ]
return r ;
^
10
✆✌
When integer variable ‘r’ is declared as static, the compiler gives output without
warning.

# include < stdio .h >
2 int * myF ( ) {
static int r [1];
4 r [0]=10;
return r ;
6 }
int main () {
8 int * p ;
p = muF () ;
10 printf ( " % d \ n " , * p ) ;
return 0;
12 }
✆✌

10
✆✌
1.3. VARIABLES 81

extern Qualifier
extern is used when a file needs to access a variable in another file that it may not have
#include directly. Therefore, extern does not actually carve out space for a new variable,
it just provides the compiler with sufficient information to access the remote variable.

Property Default Value


Keyword used extern
Storage Memory
Default value Zero
Scope Global (all over the program)
Life Time Value persists till the program’s execution
Optionality Optional if declared outside all the functions

Table 1.12: Features of extern variable.

The syntax of this qualifier is



1 /* Implicit declaration of variable , this only described *
* and assumed allocated elsewhere , normally from include */
3 extern int AVar ;
/* Custom function that will increase external variable by one */
5 void MyFunc ( void ) {
++ AVar ;
7 }
✆✌
Assume a simple program which has three code files. First main file ‘main.c’, second
header file ‘myH.h’ and third function file ‘Incr.c’. The codes in header file ‘myH.h’, are

1 void Incr () ;
✆✌
The codes in function file ‘Incr.c’, are

1 int in =0;
void Incr () {
3 in ++;
}
✆✌
The codes in main file ‘main.c’, are

# include < stdio .h >
2 # include " myH . h "
int main () {
4 /* Try to access the ’ in ’ variable *
* declared in other program file . */
6 extern int in ;
Incr () ; /* Increments to ‘ in ’ declared in ‘ Incr . c ’ file . */
82 Basic C

8 printf ( " % d " , in ) ; /* Prints result of external ‘ in ’ */


return 0;
10 }
✆✌
By using extern qualifier, we can access to the variable ‘in’ declared and initialized in
function file ‘Incr.c’. The function ‘Incr()’ increments to the variable which is printed in
output by using printf function. The output of the above program is

1
✆✌
If the code line

1 extern int in ;
✆✌
given in above ‘main.c’ file is rewritten as

1 int in ;
✆✌
then, the program output shall be ‘0’. It is because ‘Incr()’ function increments to the
variable declared in its ‘Incr.c’ file. Inside the main() function of ‘main.c’ file, we print
output by using printf function and by this function value of locally declared ‘in’ variable
is ptrinted, which is 0 by default. See the modified codes of ‘main.c’ file

1 # include < stdio .h >
# include " myH . h "
3 int main () {
/* ‘ in ’ variable is declared locally here . */
5 int in ;
Incr () ; /* Does not increment to locally declared ‘ in ’ */
7 printf ( " % d " , in ) ; /* Prints result of local ‘ in ’ */
return 0;
9 }
✆✌

0
✆✌

volatile Qualifier
volatile is a special type modifier which informs the compiler that the value of the variable
may be changed by external entities other than the program itself. The value of volatile
variable may change between two successive readings of the variable even though program
has not modify the value of volatile type variable. It is good practice to read the variable
value each time before program tries to accessing it. volatile is relevant with embedded
systems. In embedded systems a program has not have complete control on a variable.
The syntax for volatile qualifier is

1 int volatile i ;
✆✌
See the example below in which a variable ‘i’ is declared as constant. The value of the
variable ‘i’ can not be changed by program itself.
1.3. VARIABLES 83


1 # include < stdio .h >

3 int main ( void ) {


/* Declare i as constant integer */
5 const int i = 10;
int * j = ( int *) & i ;
7 printf ( " Value of i is : % d \ n " , i ) ;
/* Try to modify value of i */
9 * j = 100;
printf ( " New value of i is : % d \ n " , i ) ;
11 return 0;
}
✆✌

Value of i is : 10
New value of i is : 10
✆✌
Now, the same variable ‘i’ is declared as constant and volatile. The value of the variable
‘i’ can be changed by program itself.

# include < stdio .h >
2

int main ( void ) {


4 /* Declare i as constant integer */
const volatile int i = 10;
6 int * j = ( int *) & i ;
printf ( " Value of i is : % d \ n " , i ) ;
8 /* Try to modify value of i */
* j = 100;
10 printf ( " New value of i is : % d \ n " , i ) ;
return 0;
12 }
✆✌

Value of i is : 10
New value of i is : 100
✆✌

auto Qualifier
auto is a modifier which specifies an “automatic” variable that is automatically created
when in scope and destroyed when out of scope. If you think this sounds like pretty much
what you’ve been doing all along when you declare a variable, you’re right: all declared
items within a block are implicitly “automatic”. For this reason, the auto keyword is
more like the answer to a trivia question than a useful modifier, and there are lots of very
competent programmers that are unaware of its existence. The automatic variable is not
initialized at all.
84 Basic C

Property Default Value


Keyword used auto
Storage Memory
Default value Garbage value or random value
Scope Local to the block in which it is defined
Life Time Value persists till the control remains within
the block
Optionality Optional

Table 1.13: Features of auto variable.

In following example, ‘b’ has declared as automatic variable and it has scope only
inside the block where it is declare. Here, ‘b’ is declared outside the main function block,
so on compilation, it shows an error.

# include < stdio .h >
2 /* Automatic variable b */
auto int b = 10;
4

int main () {
6 auto int a = 5;
a ++;
8 printf ( " % d \ n " , a ) ;
printf ( " % d \ n " , b ) ;
10 return 0;
}
✆✌
In following example, variable ‘b’ is global integer while a is defined as automatic inside
the main() function. Hence variable ‘a’ and ‘b’ are accessible inside the main() function.

1 # include < stdio .h >
/* b has declared as global . */
3 int b = 10;

5 int main () {
auto int a = 5;
7 a ++;
printf ( " a : % d \ n " , a ) ;
9 printf ( " b : % d \ n " , b ) ;
return 0;
11 }
✆✌

a : 5
b : 10
✆✌
1.3. VARIABLES 85

When defining a variable, we dont actually need to state its type explicitly when it can
be deduced from the auto initializer. With auto, we use equal (=) syntax because there
is no type conversion involved that might cause problems. See the example below:

# include < stdio .h >
2

int main () {
4 auto i = ’c ’;
printf ( " % c " , i ) ;
6 return 0;
}
✆✌

c
✆✌

register Qualifier
Storing and retrieving of data in memory is slower than storing and retrieving of data
from CPU resistors. Hence, sometime storing and retrieving of data from resistor makes
a program run faster. register is a hint to the compiler to attempt to optimize the
storage of the given variable by storing it in a register of the computer’s CPU when the
program is run. Most optimizing compilers do this anyway, so use of this keyword is
often unnecessary. In fact, ANSI C states that a compiler can ignore this keyword if it so
desires and many do.

Property Default Value


Keyword used register
Storage CPU registers (values can be retrieved faster
than from memory)
Default value Garbage value
Scope Local to the block in which it is defined
Life Time Value persists till the control remains within
the block
Optionality Mandatory to use the keyword

Table 1.14: Features of register variable.

Example for register type variable is given below.



1 # include < stdio .h >

3 int main () {
register int i ;
5

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


86 Basic C

7 printf ( " Value is % d \ n " , i ) ;


}
9 }
✆✌

Value is 0
Value is 1
Value is 2
Value is 3
Value is 4
✆✌
When a C-program is run, the main() function refers to two special purpose registers, i.e.
‘rbp’ and ‘rsp’. ‘rbp’ is the base pointer, which points to the base of the current stack
frame, and ‘rsp’ is the stack pointer, which points to the top of the current stack frame.
When a variable is added in stack, ‘rbp’ increments by one and points to next memory
cells to store next variable value. In GCC, register keyword with asm keyword provides
access to these special purpose registers directly as shown in the following example.

1 # include < stdio .h >
# include < stdlib .h >
3

int main ( void ) {


5 register long rsp asm ( " rsp " ) ;
register long rbp asm ( " rbp " ) ;
7 int i = 10; // value at rbp -0 x4
int j = 20; // value at rbp -0 x8
9 int k = 30; // value at rbp -0 x12
printf ( " rpb = % lx \ n " , rbp ) ; /* Current pointer of rbp *
11 * points next empty cell */
printf ( " a = % d \ n " , *( int *) ((( char *) rbp ) - 0 x4 ) ) ;
13 printf ( " b = % d \ n " , *( int *) ((( char *) rbp ) - 0 x8 ) ) ;
printf ( " c = % d \ n " , *( int *) ((( char *) rbp ) - 0 xc ) ) ;
15 printf ( " rsp = % lx \ n " , rsp ) ;
return (0) ;
17 }
✆✌

rpb = 22 cd 68
a = 10
b = 20
c = 30
rsp = 22 cd 40
✆✌
See another example, in which accumulator register is accessed through register keyword.

1 # include < stdio .h >

3 int main () {
int out ;
5 register char bx asm ( " ebx " ) ;
/* Add 10 and 20 and store *
7 * result into register % eax */
1.3. VARIABLES 87

__asm__ ( " movl $10 , %% eax ; "


9 " movl $20 , %% ebx ; "
" addl %% ebx , %% eax ; "
11 : " = a " ( out )
);
13 printf ( " Sum is % d \ n " , out ) ;
printf ( " bx register has % d \ n " , bx ) ;
15 return 0;
}
✆✌

Sum is 30
bx register has 20
✆✌

restrict Qualifier
restrict keyword is used with pointers only. It restricts the access of the object pointed by
pointer only through the pointer pointing to that object. It helps compiler for not further
checks. If this keyword is not used properly, result becomes undefined. This keyword is
used to optimize the assembler codes.

attribute & pragma


pragma and attribute directives are used to tell the program that which parts of the
codes shall be executed before (at run) or after (at exit) running of the main program.
#pragma does not support by gcc compiler. The use of #pragma and attribute direc-
tives is given below:

# pragma startup < func1 >
2 # pragma exit < func2 >
//
4 void __attribute_ _ (( constructor ) ) < func1 () >;
void __attribute_ _ (( destructor ) ) < func2 () >;
✆✌
See the program given below:

1 # include < stdio .h >

3 void myFuncA () ;
void myFuncB () ;
5

void __attribute_ _ (( constructor ) ) myFuncA () ;


7 void __attribute_ _ (( destructor ) ) myFuncB () ;

9 void myFuncA () {
printf ( " Inside my function A .\ n " ) ;
11 }

13 void myFuncB () {
printf ( " Inside my function B .\ n " ) ;
88 Basic C

15 }

17 int main () {
printf ( " Inside main () \ n " ) ;
19 return 0;
}
✆✌

Inside my function A .
Inside main ()
Inside my function B .
✆✌
These directives are used to warn users about the dependencies or pre-requirements of
specific libraries for the given program.

1.4 C Operators
1.4.1 Expression
An expression is a combination of one or more explicit values, constants, variables, op-
erators, and functions. The evaluated value of expression is assigned to another variable
or printed in output stream. If a function is present in an expression and the function
is declared as void return type, then returned value is discarded in that expression. For
example
y = x2 + b ∗ x + 9
is an expression of variables ‘x’ and ‘y’ while ‘b’ and ‘9’ are constants. ‘y’ is dependent
variable and other variables are either constant or independent. The terms of expression
are evaluated as their mathematical operations. Here ‘ˆ’ means power rather than bitwise
operator. ‘b’ and ‘x’ are in product (‘*’ means multiplication) and all the terms in right
hand side are in summation. The expression with function is declared as
y = x2 + myF (x)
Where ‘myF()’ is user defined function.

1.4.2 Instructions
There are three types of instructions in C. Declaration instruction, arithmetic instruction
and control instruction. Declaration instructions are used in declaration of data type,
assigning values and evaluation of operators.

1 int i ; // Declaration Instruction
int j =0; // Declaration Instruction
✆✌
Arithmetic instructions are used to perform arithmetic operations on variables and con-
stants.

int i ; // Declaration Instruction
2 int j =0; // Declaration Instruction
int k = i + j ; // Arithmetic Instruction
✆✌
1.4. C OPERATORS 89

Control instructions are used to control the flow of program. The control instructions are
if, if-else, switch statements and other conditional operators.

1 int k = 1; // Declaration Instruction
if (k >2) { // Control Instruction statement
3 printf ( " True " ) ;
} else {
5 printf ( " False " ) ;
}
✆✌

1.4.3 Unary Operators


In a unary operation, operator has only one operand. The unary operators used in C are
given in table below.

Type Representation
Increment ++x, x++
Decrement – – x, x – –
Address &x
Indirection *x
Positive +x
Negative –x
Ones’ complement ∼x
Logical negation !x
Sizeof sizeof x, sizeof (type-name)
Cast (type-name) cast-expression

In above table, ‘type-name’ is variable type, like int, char, long, double etc. ‘cast-
expression’ is variable that is being converted from one data type to other data type.

# include < stdlib .h >
2

int main () {
4 printf ( " Negative of 2 is % d \ n " , -2) ;
return 0;
6 }
✆✌

Negative of 2 is -2
✆✌
Increment operator ‘++’ is used either as prefix or suffix to a variable. Both are not same.
When ‘++’ operator is prefixed to variable then value of the variable is first incremented
90 Basic C

and then used. Similarly, when ‘++’ operator is suffix to a variable then value of variable
is used first then it is incremented.

1 /* Use then increment */
i ++;
3 /* Increment then use */
++ i ; /* Equals to i = i + 1; */
✆✌
Equivalent example for i + + is given below:

# include < stdio .h >
2

int main () {
4 int i = 9;
{ /* Begin of i ++ block */
6 printf ( " i is % d \ n " , i ) ; /* Use i */
i = i + 1; /* Then increment it */
8 } /* End of i ++ block */
return 0;
10 }
✆✌

i is 9
✆✌
Equivalent example for + + i is given below:

1 # include < stdio .h >

3 int main () {
int i = 9;
5 { /* Begin of ++ i block */
i = i + 1; /* Increment i */
7 printf ( " i is % d \ n " , i ) ; /* Then use it */

9 } /* End of ++ i block */
return 0;
11 }
✆✌

i is 10
✆✌
If increment or decrement operator is used with function parameter in a function call, then
at first variable is computed and then its value is passed to the fuction as its argument.

1 # include < stdio .h >

3 int get ( int i ) {


return i +1;
5 }

7 int main () {
int i = 2;
1.4. C OPERATORS 91

9 /* Here , ++ i = 3 and next ++ i = 4. Now , i is replaced *


* by 4. The value 4*4=16 is passed for function call */
11 printf ( " % d " , get (++ i * ++ i ) ) ; // Prints 17
return 0;
13 }
✆✌

17
✆✌
If one of the operand of a valid operator is another valid operator then it acts as unary
operator as shown in the following example.

1 # include < stdio .h >

3 int main () {
int z = 4 * -3 / -2;
5 printf ( " % d " , z ) ;
return 0;
7 }
✆✌

6
✆✌
In this example, minus sign (–) is unary operator as its preceding operand is a valid
multiplication operator. Hence, it makes number 3 and number 2 as negative numbers.

1.4.4 Binary Relation Operators


Binary operators are those operators which require two operands. These operators are
addition, subtraction, multiplication, division, less than, greater than, equals to etc. The
relational binary operators are

Operator Description
< Less than
> Greater than
≤ Less than or equal to
≥ Greater than or equal to
== Equals
!= Not equals

In relation, a < b indicates that ‘a’ is less than ‘b’ and ‘a’ may have infinite numbers
of values which are lesser than ‘b’, i.e. (−∞, b). The value of ‘a’ shall be positive or
negative depends on the value of ‘b’. a ≤ b is similar to a < b except ‘a’ can also be equal
to ‘b’, i.e. (−∞, b]. a == b indicates than ‘a’ is exactly equal to ‘b’ and ‘a’ have no other
value than ‘b’. a! = b means ‘a’ never be equal to ‘b’. ‘a’ may be lesser than or greater
than ‘b’, i.e. (−∞, ∞)-(b).
92 Basic C


1 # include < stdio .h >
# include < string .h >
3

int main ( void ) {


5 int a = 5;
int b = 2;
7 int c = 5;
if ( a < b )
9 printf ( " % d is less than % d .\ n " , a , b ) ;
if ( a > b )
11 printf ( " % d is greater than % d .\ n " , a , b ) ;
if ( a <= c )
13 printf ( " % d is either less than or equal to % d .\ n " , a , c );
if ( a == c )
15 printf ( " % d is exactly equal to % d .\ n " , a , c ) ;
if ( a != b )
17 printf ( " % d is not equal to % d .\ n " , a , b ) ;
return 0;
19 }
✆✌
Output of above program is

5 is greater than 2.
5 is either less than or equal to 5.
5 is exactly equal to 5.
5 is not equal to 2.
✆✌
Remember that ‘=’ and ‘==’ are not same. ‘=’ is used to assign a value to a variable
and ‘==’ is used for comparison. For example, ‘c=20’ assigned the value 20 to variable
c and returns true in output rather than comparing of c to 20. This is why, because C
does not have a dedicated boolean type. So ‘0’ means false and anything else is true.

int a = 20; // constant initialized
2 /* constant reassigned as 10 and *
* a becomes 10 and returns true */
4 if ( a = 10)
printf ( " Stuff " ) ; // printing of this value .
✆✌

1 # include < stdio .h >

3 int main () {
int i = 10;
5 int j = 20;
if ( i = j ) // its true though i is not equal to j .
7 printf ( " i is equal to j .\ n " ) ; // will be printed .
if ( i == j )
9 printf ( " i is perfectly equal to j .\ n " ) ; // will be printed .
}
✆✌
1.4. C OPERATORS 93


i is equal to j .
i is perfectly equal to j .
✆✌
Again to be noted that, the equal operator (‘==’) is applicable between two values
or between two variables or between a value and a variable. It is not applicable with
references, i.e. pointers as they points to address not to values. For example

# include < stdio .h >
2

int main () {
4 int * a , * b ; // two integer type pointers
a = malloc (4) ; // allocate memory for ptr a
6 b = malloc (4) ; // allocate memory for ptr b
* a = 10; // store value for a
8 * b = 10; // store value for b
if ( a == b ) { // REFERENCE comparison
10 printf ( " Equal \ n " ) ;
} else {
12 printf ( " Not Equal \ n " ) ;
}
14 return 0;
}
✆✌

Not Equal
✆✌
Now above example is modified as shown below:

1 # include < stdio .h >

3 int main () {
int * a , * b ; // two integer type pointers
5 a = malloc (4) ; // allocate memory for ptr a
b = malloc (4) ; // allocate memory for ptr b
7 * a = 10; // store value for a
* b = 10; // store value for b
9 if (* a == * b ) { // VALUE comparison
printf ( " Equal \ n " ) ;
11 } else {
printf ( " Not Equal \ n " ) ;
13 }
return 0;
15 }
✆✌

Equal
✆✌
Similarly we should avoid comparison like

1 # include < stdio .h >
int main () {
94 Basic C

3 int v = 20;
if (0 < v < 10) {
5 printf ( " Stuff " ) ;
} else {
7 printf ( " noStuff " ) ;
}
9 return 0;
}
✆✌

Stuff
✆✌
In above example, ‘v’ is greater than 0. Hence in first comparison, construct assign
value 1 to variable ‘v’. Now, value of variable ‘v’ is compared to 10, which is true, so
the statement block of if construct is executed. The appropriate form of comparison is
shown in below example.

1 # include < stdio .h >
int main () {
3 int v = 20;
if (0 < v && v < 10) {
5 printf ( " Stuff " ) ;
} else {
7 printf ( " noStuff " ) ;
}
9 return 0;
}
✆✌

noStuff
✆✌

1.4.5 Comma Operator


Comma operator (,) is a binary operator that evaluates its first operand and discards
the result, and then evaluates the second operand and returns this value. In strings,
comma operator acts as a separator. If comma separated expressions are enclosed inside
the parentheses, then last expression is evaulated. The comma operator has the lowest
precedence. When comma operator is combined with semicolon, then semicolon has lower
precedence than comma.

1 a , b ; c , d ; = > (a , b ) ; ( c , d ) ;
✆✌
Example, when expression is separated by comma and enclosed within parantheses

1 # include < stdio .h >

3 int main () {
int i = 10;
5 int j = 5;
/* First expression is evaluated and its result is discarded */
1.4. C OPERATORS 95

7 printf ( " % d " , (i , j ) ) ;


return 0;
9 }
✆✌

5
✆✌
Example, when expression is separated by comma and not enclosed within parantheses

1 # include < stdio .h >

3 int main () {
int i = 10;
5 int j = 5;
printf ( " % d " , i , j ) ; // First expression is evaluated here
7 return 0;
}
✆✌

10
✆✌
Above result is obtained with compilar warning. Another example

1 # include < stdio .h >

3 int main () {
int i = 10;
5 int j = 5;
/* First expression is evaluated and its *
7 * result is discarded but its result is *
* used in evaluation of second expression . */
9 printf ( " % d " , (i , i + j ) ) ;
return 0;
11 }
✆✌

15
✆✌
If multiple expressions separated by comma operator, are returned by return keyword,
then only last expression is returned while others are just discarded.

1 # include < stdio .h >

3 int myRet () {
return 1 , 2 , 3; // Last expression is evaluated
5 // and returned by return
}
7 int main () {
printf ( " % d " , myRet () ) ;
9 return 0;
}
✆✌
96 Basic C


3
✆✌
If multiple expressions separated by comma operator, are assigned to a variable then only
last expression is assigned while others are just discarded.

1 # include < stdio .h >

3 int main () {
// Last expression is assigned to i
5 int i = (1 , 2 , 3) ;
printf ( " % d " , i ) ;
7 return 0;
}
✆✌

1.4.6 Bitwise Operator


A bitwise OR (|) gives result ‘1’ if either one or both bits are ‘1’ otherwise result is zero.
A bitwise AND (&) gives result ‘1’ if both bits are ‘1’ otherwise result is zero. A bitwise
XOR (ˆ) results ‘1’ if only either of two bits1 are ‘1’ otherwise result is zero. A bitwise
NOT (∼) or complement, is a unary operation that performs logical negation on each bit,
forming the ones’ complement of the given binary value. Bits those are 0 become 1, and
those that are 1 become 0.

# include < stdio .h >
2

int main () {
4 /* 10 is Binary equivalent to 1010 */
int i = 10;
6 /* 5 is Binary equivalent to 0101 */
int j = 5;
8 /* - - - - - - - - - - - - - - - - - - - - - - - - - -**
Bitwise OR Operation is
10 1010
0101
12 ------
1111 = 15
14 ** - - - - - - - - - - - - - - - - - - - - - - - - - - */
printf ( " Bitwise OR of %d , % d is % d .\ n " , i , j , ( i | j ) ) ;
16 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - -**
Bitwise AND Operation is
18 1010
0101
20 ------
0000 = 0
22 ** - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
printf ( " Bitwise AND of %d , % d is % d .\ n " , i , j , ( i & j ) ) ;
24 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - -**
1
If both bits are opposite bits.
1.4. C OPERATORS 97

Bitwise XOR Operation is


26 1010
0101
28 ------
1111 = 15
30 ** - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
printf ( " Bitwise XOR of %d , % d is % d .\ n " , i , j , ( i ^ j ) ) ;
32 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -**
Bitwise NOT Operation is
34 00001010 = 10 ( decimal )
-------------------------------------
36 11110101 = 117 ( signed ) =117 -128= -11
** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
38 printf ( " Bitwise NOT of % d is % d .\ n " , i , ~ i ) ;
return 0;
40 }
✆✌

Bitwise OR of 10 , 5 is 15
Bitwise AND of 10 , 5 is 0.
Bitwise XOR of 10 , 5 is 15.
Bitwise NOT of 10 is -11.
✆✌
The precedence for evaluation of Boolean expression are parentheses, NOT, AND and
OR bitwise operators from high to low. Normally, bitwise & operator returns the value
equal to or less than the lesser operand. This is why & operator is used to restrict the
upper limit of the random result.

# include < stdio .h >
2 # include < stdlib .h >

4 int main ( void ) {


int i = 0;
6 while ( i < 10) {
printf ( " % d &% d = >% d , \ t " , i , 5 , i & 5) ;
8 i ++;
}
10 printf ( " \ n " ) ;
return EXIT_SUCCESS ;
12 }
✆✌

0&5 = > 0 , 1&5 = > 1 , 2&5 = > 0 , 3&5 = > 1 , 4&5 = > 4 ,
5&5 = > 5 , 6&5 = > 4 , 7&5 = > 5 , 8&5 = > 0 , 9&5 = > 1 ,
✆✌
While bitwise | operator returns the value equal to or larger than the largest operand.
This is why | operator is used to restrict the lower limit of random result.

# include < stdio .h >
2 # include < stdlib .h >

4 int main ( void ) {


98 Basic C

int i = 0;
6 while ( i < 10) {
printf ( " % d |% d = >% d , \ t " , i , 5 , i | 5) ;
8 i ++;
}
10 printf ( " \ n " ) ;
return EXIT_SUCCESS ;
12 }
✆✌

0|5= >5 , 1|5= >5 , 2|5= >7 , 3|5= >7 , 4|5= >5
5|5= >5 , 6|5= >7 , 7|5= >7 , 8|5= >13 , 9|5= >13
✆✌

1.4.7 Logical Operator


C has no dedicated boolean type. This is why, it returns 0 on true state and any other
value on false state. In C, the false state returns certain error codes. These certain codes
are either pre-implemented in libraries are user implemented in the user defined functions.
For example, in strcmp() function, when two strings as arguments of this function are
exactly same then it returns 0 otherwise it returns -1. In C, Logical operators are those
operators which compare the variables logically.

Operator Description
&& Logical AND. If both the operands are non-zero, then
condition becomes true. The two operands may be
equal or unequal
|| Logical OR. If any of the two operands are non-zero,
then condition becomes true. It is not matter that
both operands are equal or not.
! Logical NOT. Use to reverses the logical state of its
operand. If a condition is true then Logical NOT
operator will make false.

The precedence for evaluation of Boolean expression are parentheses, NOT, AND and
OR logic operators from high to low.

# include < stdio .h >
2

int main () {
4 int i = 10; /* Not zero , hence true value . */
int j = 20; /* Not zero , hence true value . */
6 int k = 0; /* Zero , hence false value . */
/* print "1" if both integers are not zero . */
8 printf ( " && relation between %d , % d is % d .\ n " , i , j , i && j ) ;
/* print "0" if any of two integers are zero . */
10 printf ( " && relation between %d , % d is % d .\ n " , i , k , i && k ) ;
1.4. C OPERATORS 99

/* print "1" if any of two integers are not zero . */


12 printf ( " || relation between %d , % d is % d .\ n " , i , j , i || j ) ;
return 0;
14 }
✆✌

&& relation between 10 , 20 is 1.
&& relation between 10 , 0 is 0.
|| relation between 10 , 20 is 1.
✆✌
It is remembered that bitwise operation is performed between bits of binary
numbers while logical operation is performed between two operand either
binary or integer. Logical expressions are evaluated from left to right. Evaluation
stops as soon as something is discovered that renders the expression false.

1 # include < stdio .h >

3 int main ( int argc , char * argv [ ]) {


/* Here 6 is greater than 2. And it is true .*
5 * true value is logically ANDED with 3 and *
* if result is equal to 3 then print value *
7 * is 1 otherwise print value is 0. */
printf ( " Expression result is % d \ n " , 6 > 2 && 3 == 3) ;
9 return 0;
}
✆✌

Expression result is 1
✆✌

1 # include < stdio .h >

3 int main ( int argc , char * argv [ ]) {


int x =6;
5

/* Here x is equal to 6. So , the relation *


7 * x != 6 is false . Now second relation *
* x / 2 < 5 is not evaluated here . So , *
9 * the result is 0. */

11 printf ( " Expression result is % d \ n " , x != 6 && x / 2 < 5) ;


return 0;
13 }
✆✌

Expression result is 0
✆✌

1 # include < stdio .h >

3 int main ( int argc , char * argv [ ]) {


int x =4;
100 Basic C

/* Here x is not equal to 6. So , that *


7 * x != 4 is true . Now second relation *
* x / 2 < 5 is logically ANDED with *
9 * the result of x != 6. Here x /2 is 2*
* and 2 is less than 5 , so logical *
11 * AND of left and right values is 1 */

13 printf ( " Expression result is % d \ n " , x != 6 && x / 2 < 5) ;


return 0;
15 }
✆✌

Expression result is 1
✆✌
A point shall be remember here, that evaluation of an expression is discontinued if the
value of a conditional expression is determined early. See the example below:

1 # include < stdio .h >

3 int main () {
int i ;
5 int j = 0;
for ( i = 0; i < 5; i ++) {
7 if (( i > 3) || ( j > 4) )
printf ( " Sr No %d , first line \ n " , i ) ;
9 else
printf ( " Sr No %d , second line \ n " , i ) ;
11 }
}
✆✌
In above example, ‘i’ is incremented from 0 to 4, while ‘j’ keep always equal to 0. This
is why, j > 0 is always false. While ‘i’ is less than or equal to 3, if () condition remains
false and codes within else block are executed. When ‘i’ becomes larger than 3, codes
within if () block are executed even when condition or j remains false. This is due that
OR operator returns true result. The output of this program is

Sr No 0, second line
Sr No 1, second line
Sr No 2, second line
Sr No 3, second line
Sr No 4, first line
✆✌

1.4.8 Shift Operator


The logical shift operators defined in C are shown in the following table.
1.4. C OPERATORS 101

Operator Description
<< Left shift
>> Right shift

In the following figure, a character byte is shifted by one bit in right ward. After
shifting of bits of the byte, new value is different from the old value.

One byte

ch 1 0 0 1 1 0 1 1

ch >> 1 0 1 0 0 1 1 0 1 1

Above, a byte is shifted rightward by one place. Note that, in computer memory, data
is arranged in continuous memory bytes. Here, the LSB bit, that is shifted rightward
appears that it takes place of its neighbouring bit which is beyond the range of original
memory byte. But actually, in bit shift, shifted bit does not over write to the data stored
in its neighbouring memory byte but it is eliminated from its original place to create
space for storing of its leftward bit.

One byte

ch 1 0 0 1 1 0 1 1

ch << 1 1 0 0 1 1 0 1 1 0 0

Figure 1.3: Left shift of bits by one place.

Above, a byte is shifted leftward by one place. In the similar principle to the rightward
bitshift, shifted bit does not over write to the data stored in its neighbouring memory
byte but it is eliminated from its original place to create space for storing of its rightward
bit. Example is given below:

1 # include < stdio .h >

3 int main () {
/* Bit pattern of decimal 4 is *
102 Basic C

5 * equivalent to binary 100 */


int i = 4;
7 /* Number of places take place by binary shift . */
int j = 2;
9 /* << makes 100 to 10000 & print "16" */
printf ( " << of %d , % d is % d .\ n " , i , j , i << j ) ;
11 /* >> makes 100 to 1 & print "1" */
printf ( " >> of %d , % d is % d .\ n " , i , j , i >> j ) ;
13 return 0;
}
✆✌

<< of 4 , 2 is 16.
>> of 4 , 2 is 1.
✆✌
If a data type is unsigned type and it is assigned a negative number then its bit shift
takes placed for whole bits as shown in the following example. Note that, the vacated
bits are filled with zero bits.

# include < stdio .h >
2

int main () {
4 unsigned char f = 0 , c = -16;
printf ( " Original Number % d \ n " , c ) ;
6 f = c >> 2;
printf ( " >> shifts number and number becomes % d \ n " , f ) ;
8 f = c << 2;
printf ( " << shifts number and number becomes % d \ n " , f ) ;
10 return 0;
}
✆✌

Original Number 240
>> shifts number and number becomes 60
<< shifts number and number becomes 192
✆✌
If a data type is signed type and it is assigned a negative number then its bit shift takes
placed for whole bits except the sign bit (MSB) as shown in the following example. Note
that, the vacated bits are filled with zero bits.

1 # include < stdio .h >

3 int main () {
signed char f = 0 , c = -16;
5 printf ( " Original Number % d \ n " , c ) ;
f = c >> 2;
7 printf ( " >> shifts number and number becomes % d \ n " , f ) ;
f = c << 2;
9 printf ( " << shifts number and number becomes % d \ n " , f ) ;
return 0;
11 }
✆✌
1.4. C OPERATORS 103


Original Number -16
>> shifts number and number becomes -4
<< shifts number and number becomes -64
✆✌
Bitwise AND & XOR relations may also be used to add two number. AND operation
tells the positions of bits where carry generated and this carry is to be shifted/added to
leftside bit. XOR operation is used to get the binary addition ignoring carry generated if
anywhere.

1 # include < stdio .h >

3 int main () {
unsigned int x = 30 , y = 1 , sum , carry ;
5 /* - - - - - - - - - - - - - - - - - - - - - - - - - - -**
* Decimal 30 is binary 11110
7 * Decimal 01 is binary 00001
* XOR Operation is
9 * 11110
* 00001
11 * ---------
* S = 11111
13 ** - - - - - - - - - - - - - - - - - - - - - - - - - - - */
sum = x ^ y ;
15 /* - - - - - - - - - - - - - - - - - - - - - - - - - - -**
* Decimal 30 is binary 11110
17 * Decimal 01 is binary 00001
* AND Operation is
19 * 11110
* 00001
21 * ----------
* C = 00000
23 ** - - - - - - - - - - - - - - - - - - - - - - - - - - - */
carry = x & y ;
25 /* Performed loop until last carry is not zero . */
while ( carry != 0) {
27 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -**
* Left shift of carry is
29 * C_s = 000000
* This operation is performed to shift
31 * the carry left hand side by one place
* to add it with next higher place value .
33 ** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
carry = carry << 1;
35 /* Take x as sum value from XOR Operation . */
x = sum ;
37 /* Take y as carry value form *
* left shift of AND Operation . */
39 y = carry ;
/* Take XOR Operation of x and y */
41 sum = x ^ y ;
/* Get the next carry . */
104 Basic C

43 carry = x & y ;
}
45 /* Print the sum 31. */
printf ( " Sum of % d and % d is : % d \ n " , x , y , sum ) ;
47 return 0;
}
✆✌

Sum of 30 and 1 is 31
✆✌
Binary shift operation can be performed in characters and strings. It is explained in the
example given below.

1 # include < stdio .h >

3 int main () {
char a [ ]= " a " ; /* Binary equivalent -1100001 */
5 char b [ ]= " b " ; /* Binary equivalent -1100010 */
char c [ ]= " c " ; /* Binary equivalent -1100011 */
7 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*
<< of a by 16 places 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
9 << of b by 8 places 110001000000 00 0
<< of a by 0 places 1100011
11 ----------------------------------------------
OR Operation 11000010110001001100011
13 Hexadecimal 616263
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
15 printf ( " Left binary bit shift % xh \ n " )
printf (* a << 16 | * b < <8 | * c ) ;
17 return 0;
}
✆✌

Left binary bit shift is 616263 h
✆✌
The unary operator ‘∼’ returns the one’s complements of an integer by changing bit ‘0’
into ‘1’ and viceversa.

1 # include < stdio .h >
# include < stdlib .h >
3

int main ( void ) {


5 int j = 0;
printf ( " Bitwise ~ operation on an integer .\ n " ) ;
7 while ( j < 3) {
printf ( " % d = > % d \ n " , j ,~ j ) ;
9 j ++;
}
11 return EXIT_SUCCESS ;
}
✆✌
1.4. C OPERATORS 105


Bitwise ~ operation on an integer .
0 = > -1
1 = > -2
2 = > -3
✆✌
Note that, shift operator is applied only to those byte(s) which are pointed by the variable.
On shift operation, values of neighbouring bytes remain unaffected and un-altered. It
means, in shift operation, bits are neither borrows nor carryover from or to neighbouring
memory bytes. See the example below:

# include < stdio .h >
2

int main () {
4 int a = 320;
/* Integer 320 = binary 00000001 01000000 */
6 char * ptr ;
ptr = ( char *) & a ;
8

char ca = * ptr ; /* Get 01000000 as decimal 64 */


10 char cb = *(++ ptr ) ; /* Get 00000001 as decimal 1 */

12 printf ( " % d " , ca ) ;


printf ( " % d " , cb ) ;
14

cb = ( cb << 5) ; /* Shift the value of cb . */


16

printf ( " % d " , ca ) ; /* Print 01000000 as decimal 64 */


18 printf ( " % d " , cb ) ; /* Print 00100000 as decimal 32 */

20 return 0;
}
✆✌

64 1 64 32
✆✌
In above example, bit shift of ‘cb’ does not affects the value of ‘ca’ any way.

1.4.9 Condition & Relation Operators


If a condition is true then successive value is taken otherwise next value. The simplest
form of this operator is

1 x ? y : z
✆✌
See the example below:

1 # include < stdio .h >
# include < io .h >
3

/* Return true if file exist other wise return false . */


106 Basic C

5 int file_exists ( char * filename ) {


return ( access ( filename , 0) == 0) ;
7 }

9 main () {
printf ( " Does myfile . au exist : % s \ n " ,
11 file_exists ( " myfile . au " ) ? " YES " : " NO " ) ;
}
✆✌

Does myfile . au exist : NO
✆✌

1.4.10 Lexical Comparison


Lexical comparison is performed between two strings having alpha-numeric and special
characters. Both strings are compared character-by-character and comparison is done
between the charcter codes. For example, ‘a’ and ‘A’ are same characters but their
character codes are 97 and 65 respectively. Therefore, in lexical comparison, character ‘a’
is larger than ‘A’.

str1 s i m p l e

str2 s i M p l e

Lexical comparision between strings “simple” and “siMple” is taken character by


character. In ASCII character codes, character “M” came before to “m”, this is why in
character by character comparison, ‘str1’ is greater than the ‘str2’.

1.4.11 Arithmetic Operators


Arithmetic operators are given in the following table.
1.4. C OPERATORS 107

Operator Description
+ Addition operator. It adds the right
value with left value.
− Subtraction operator. It subtracts the
right value from left value.
/ Division operator. It divides the left
value with right value. Returns the
quotient. If, both left and right values
are integer then decimal part of the re-
sult is truncated.
∗ Multiplication operator. It multiply the
left value with right value. Returns
product of two numbers.
% It is modulus operator. It returns the
remainder of division between two num-
bers. It accepts only integer type val-
ues as its operands.
= Assignment operator. A variable, at
left side to it, is assigned the value at
the right side of it.

Table 1.15: Arithmetic operators.

See the example below, in which addition and subtraction operators are used in a
single expression.

1 # include < stdio .h >

3 int main () {
int y ;
5 /* In first step 5+3=8. In *
* second step 8 -4 = 4. As *
7 * + has higher precedence */
y = 5 + 3 - 4;
9 printf ( " Result is : % d \ n " , y);
return 0;
11 }
✆✌

Result is : 4
✆✌
The grouping of terms in a mathematical expression, using parentheses is required to get
correct result when an arithmetic operator is used multiple times. If grouping is not done
then result is different.

1 # include < stdio .h >
108 Basic C

3 int main () {
float a ;
5

/* / operator is used thrice .*


7 * will be solved from L to R . */
a = 20.0 / 10.0 / 2.0;
9 printf ( " Result is % f \ n " , a ) ;

11 /* First 10.0 is divided by 20.0 and *


* then result will divide to 20.0 */
13 a = 20.0 / (10.0 / 2.0) ;

15 printf ( " Result is % f \ n " , a ) ;


return 0;
17 }
✆✌

Result is 1.000000
Result is 4.000000
✆✌
If grouping is not done, i.e. there is no parentheses, then in C, expression is solved from
left to right maintaining the precedence for mathematical operators.

# include < stdio .h >
2

int main () {
4 float a ;

6 /* / operator is used thrice .*


* will be solved from L to R . */
8 a = 20.0 / 10.0 / 2.0;
printf ( " Result is % f \ n " , a ) ;
10

a = 2.0 / 10.0 / 20.0;


12 printf ( " Result is % f \ n " , a ) ;
return 0;
14 }
✆✌

Result is 1.000000
Result is 0.010000
✆✌
Note that if operators in an expression or in a term of the expression are in same prece-
dence level/order then they all are solved from left to right in the given expression.

# include < stdio .h >
2

int main () {
4 int a ;

6 /* Here , / , * and % operators are *


1.4. C OPERATORS 109

* in same precedence order . */


8 a = 2 * 10 / 20 % 5;
printf ( " Result is % d \ n " , a ) ;
10

a = 2 % 10 * 20 / 5;
12 printf ( " Result is % d \ n " , a ) ;
return 0;
14 }
✆✌

Result is 1
Result is 8
✆✌
Take another example as given below:

# include < stdio .h >
2

int main () {
4 int a = 1 , b = 2 , c = 3;
printf ( " % d " , c > b > a ) ;
6 return 0;
}
✆✌

0
✆✌
In above case, first value of ‘c’ is compared with value of ‘b’ which is false as per expression,
hence the result is ‘0’. Now this value is compared with value of ‘a’ which is again false
as per expression, hence the final result is ‘0’. Now, modify the above example as given
below:

1 # include < stdio .h >

3 int main () {
int a = -1 , b = 2 , c = 3;
5 printf ( " % d " , c > b > a ) ;
return 0;
7 }
✆✌

1
✆✌
Here first value of ‘c’ is compared with value of ‘b’ which is false as per expression,
hence the result is ‘0’. Now this value is compared with value of ‘a’ which is true as per
expression, hence the final result is ‘1’.

1.4.12 Relational Operators


The relation and assignment operators are given in the table 1.16. The level of precedence
of the operators given in table 1.16 are equal, hence, they are solved from left to right in
an expression where they are present. See the following example, in which application of
‘+=’ operator is explained.
110 Basic C

Operator Description
== It accepts two operands and it meant that the operands are
exactly equal.
∗= Product and equal. Current value of left side is multiply
by right side value and result is assigned to the left side
variable.
/= Divide and equal. Current value of left side is divided by
right side value and result is assigned to the left side vari-
able.
+= Add and equal. Current value of left side is added by right
side value and result is assigned to the left side variable.
−= Subtract and equal. Current value of left side is subtracted
by right side value and result is assigned to the left side
variable.
<<= Left shift and equal. It makes left shift to the current value
of the left side variable by the exactly equal places to the
number given in right side. Its operands are either integer
or character only and shall not be precision values.
>>= Right shift and equal. It makes right shift to the current
value of the left side variable by the exactly equal places
to the number given in right side. Its operands are either
integer or character only and shall not be precision values.
&= AND and equal. Perform AND operation between current
value of left hand side variable and right hand side value
and assign the result to left hand side variable.
ˆ= Exclusive OR and equal. Perform Exclusive OR operation
between current value of left hand side variable and right
hand side value and assign the result to left hand side vari-
able.
|= Inclusive OR and equal. Perform Inclusive OR operation
between current value of left hand side variable and right
hand side value and assign the result to left hand side vari-
able.

Table 1.16: Relation & assignment operators.


1.4. C OPERATORS 111


1 # include < stdio .h >

3 int main () {
int y = 1;
5 y += 2; /* It is equal to y = y + 2; */
printf ( " y is % d \ n " , y ) ;
7 int z = 1;
z -= 2; /* It is equal to z = z - 2; */
9 printf ( " z is % d \ n " , z ) ;
return 0;
11 }
✆✌

y is 3
z is -1
✆✌
Following example is for ‘/=’ operator.

# include < stdio .h >
2

int main () {
4 double y = 2.0;
y /= 3.0; /* It is equal to y = y / 3.0; */
6 printf ( " y is % f \ n " , y ) ;
return 0;
8 }
✆✌

y is 0.66666
✆✌
Example of left shift & equal and right shift & equal operators is given below.

1 # include < stdio .h >

3 int main () {
int y = 9;
5 y < <= 2; /* It is equal to y = y << 2; */
printf ( " y is % d \ n " , y ) ;
7 int z = 10;
z > >= 2; /* It is equal to z = y >> 2; */
9 printf ( " z is % d \ n " , z ) ;
return 0;
11 }
✆✌

y is 36
z is 2
✆✌
112 Basic C

1.4.13 Bit Field


A bit field is just a set of neighboring bits within a signed integer or an unsigned integer.
The syntax of the bit field structure is

struct {
2 unsigned int < field name > : < bit size >;
unsigned int < field name > : < bit size >;
4 };
✆✌
Or

struct {
2 unsigned < field name > : < bit size >;
unsigned < field name > : < bit size >;
4 };
✆✌
Always remember that, bit size of field declared inside the bit field structure, can not be
larger than the size of field. And unsigned integer is 4 byte long, hence bit size of it can
not be larger than 8 × 4 = 32 bits. A bit field is set up with a structure declaration that
labels each field and determines its width.

struct {
2 unsigned int boldface : 1;
unsigned int slant : 1;
4 } font ;
✆✌
This structure definition causes ‘font’ to contain two 1-bit fields. We can assigned the
value to these structure field by

font . slant =0;
2 font . boldface =1;
✆✌
It can be “pad” a field structure with unnamed holes by using unnamed field widths.
Using an unnamed field width of 0 forces the next field to align with the next integer.

struct {
2 unsigned int f1 : 1;
unsigned int : 2;
4 unsigned int f2 : 3;
} field ;
✆✌
Often bit fields are used as a more compact way of storing data.

1 # include < stdio .h >

3 struct employee {
unsigned id : 8; /* Or use unsigned int id :8; */
5 unsigned sex : 1; /* Or use unsigned int sex :1; */
unsigned age : 7; /* Or use unsigned int age :7; */
7 };
1.4. C OPERATORS 113

9 int main () {
struct employee EmpNo ;
11 EmpNo . id = 102;
EmpNo . sex = 1;
13 EmpNo . age = 15;
printf ( " % d \ t % d \ t % d \ n " , EmpNo . id , EmpNo . sex , EmpNo . age ) ;
15 return 0;
}
✆✌

102 1 15
✆✌
In above example, bits are filed from right to left direction. Here 8 bits are used for id, 1
bit for sex and 7 bit for age. In following example, natural color is made of three prime
colors red, green and blue. To store these colors in program a three bit data storage is
used.

Bit Pattern Decimal Color


000 0 Black
001 1 Red
010 2 Green
011 3 Yellow
100 4 Blue
101 5 Magenta
110 6 Cyan
111 7 White

Table 1.17: Bit color storing.

These colors are used in structure ‘colstr’ and #define is used to create symbolic
constants for the possible member values.

1 # include < stdio .h >
# define BLUE 4
3 # define GREEN 2
# define RED 1
5 /* mixed colors */
# define BLACK 0
7 # define YELLOW ( RED | GREEN )
# define MAGENTA ( RED | BLUE )
9 # define CYAN ( GREEN | BLUE )
# define WHITE ( RED | GREEN | BLUE )
11 const char * colors [8] = { " black " , " red " , " green " , " yellow " ,
" blue " , " magenta " , " cyan " , " white " };
13
114 Basic C

struct colstr {
15 unsigned int fill_color : 2;
unsigned int border_color : 4;
17 };

19 void show_colrs ( const struct colstr * pb ) ;

21 int main ( void ) {


/* create and initialize box_props structure */
23 struct colstr box = { YELLOW , GREEN };
printf ( " Original box settings :\ n " ) ;
25 show_colrs (& box ) ;
box . fill_color = WHITE ;
27 box . border_color = MAGENTA ;
printf ( " \ nModified box settings :\ n " ) ;
29 show_colrs (& box ) ;
return 0;
31 }

33 void show_colrs ( const struct colstr * pb ) {


printf ( " The fill color is % s .\ n " , colors [ pb - > fill_color ]) ;
35 printf ( " The border color is " ) ;
switch ( pb - > border_color ) {
37 case MAGENTA : printf ( " magenta .\ n " ) ;
break ;
39 case RED : printf ( " red .\ n " ) ;
break ;
41 default : printf ( " unknown color .\ n " ) ;
break ;
43 }
}
✆✌

Original box settings :
The fill color is yellow .
The border color is unknown color .

Modified box settings :


The fill color is yellow .
The border color is magenta .
✆✌
Size of bit field structure is determined by the number of fields and bit size of the fields.
An unsigned integer is of word size of 4 byte. Hence minimum size of bit field structure is
4 byte. If there are four fields in a bit field structure then first four byte space is allotted
to accommodate total bits of the fields of the bit field structure. If size of bits of all fields
in a bitfield structure is larger than the 4 bytes then next four byte space is added to
accommodate the all bits of fields of the bit field structure. Following examples clarify it
correctly.

1 # include < stdio .h >
1.4. C OPERATORS 115

3 struct bitfield {
/* First four byte ( size of int ) is allocated . */
5 unsigned int a : 2; // 2 bits +
unsigned int b : 2; // 2 bits + - > Total 5 bits < 32 bits
7 unsigned int c : 1; // 1 bits +
/* Though there are int fields but all *
9 * bits are accomodated in four bytes ,*
* only four byte space is allocated . */
11 };

13 int main () {
struct bitfield bF ;
15 printf ( " Size of bitfield struct is : % d " , sizeof ( bF ) ) ;
return 0;
17 }
✆✌

Size of bitfield struct is : 4
✆✌
In following example the bit size of variables ‘a’, ‘b’ and ‘c’ are changed to 12, 12 and 1
respectively. Total sum of bits is 25 which is much lesser than 32. Hence size of structure
is 4 byte.

1 # include < stdio .h >

3 struct bitfield {
/* First four byte ( size of int ) is allocated . */
5 unsigned int a : 12; // 12 bits +
unsigned int b : 12; // 12 bits + - > Total 25 bits < 32 bits
7 unsigned int c : 1; // 1 bits +
/* Though there are int fields but all *
9 * bits are accomodated in four bytes ,*
* only four byte space is allocated . */
11 };

13 int main () {
struct bitfield bF ;
15 printf ( " Size of bitfield struct is : % d " , sizeof ( bF ) ) ;
return 0;
17 }
✆✌

Size of bitfield struct is : 4
✆✌
In following example the bit size of variables ‘a’, ‘b’ and ‘c’ are changed to 12, 12 and 10
respectively. Total sum of bits is 34 which is larger than 32. Hence size of structure is 8
byte.

1 # include < stdio .h >

3 struct bitfield {
/* First four byte ( size of int ) is allocated . */
116 Basic C

5 unsigned int a : 12; // 12 bits +


unsigned int b : 12; // 12 bits + - > Total 34 bits > 32 bits
7 unsigned int c : 10; // 10 bits +
/* Though there are int fields but all *
9 * bits can not be accommodated in four *
* bytes . Hence extra four bytes space *
11 * is allocated . Here total allocated *
* space is 8 bytes long . Net bitfield *
13 * struct size is 8 bytes long . */
};
15

int main () {
17 struct bitfield bF ;
printf ( " Size of bitfield struct is : % d " , sizeof ( bF ) ) ;
19 return 0;
}
✆✌

Size of bitfield struct is : 8
✆✌
A field of a bit field struct is assigned a numeric value, it is accepted as binary number.
As the bit field is restricted to specific size, hence number of bits of a number equal to
the size of bit field are taken. Counting of bits of given number is started from right to
left upto the bit size of the bit field. Rest of the bits are truncated. These bits are stored
in the structure memory space allocated previously. The order of storing data in memory
space is from right to left and first field data is stored at right most and subsequent field
data is stored leftword respectively. See following examples for clarification of this para.

1 # include < stdio .h >

3 struct bitfield {
/* Last three bits 001 of binary *
5 * 00000001 are omitted and stored */
unsigned int a : 3;
7 /* Last three bits 100 of binary *
* 00000100 are omitted and stored */
9 unsigned int b : 3;
/* Last three bits 111 of binary *
11 * 00110111 are omitted and stored */
unsigned int c : 3;
13 };

15 int main () {
/* Four byte space is created . */
17 struct bitfield bF ;
bF . a = 1; /* Binary equivalent to 00000001 */
19 bF . b = 4; /* Binary equivalent to 00000100 */
bF . c = 55; /* Binary equivalent to 00110111 */
21 printf ( " Size of bitfield struct is : % d \ n " , sizeof ( bF ) ) ;
printf ( " Bit field c has value : % d \ n " , bF . c ) ;
23 return 0;
1.4. C OPERATORS 117

}
✆✌

Size of bitfield struct is : 4
Bit field c has value : 7
✆✌
In following example, bit size of bit field ‘c’ is changed to 5. Now the stored value in bit
field ‘c’ is different to the data stored in previous example.

# include < stdio .h >
2

struct bitfield {
4 /* Last three bits 001 of binary *
* 00000001 are omitted and stored */
6 unsigned int a : 3;
/* Last three bits 100 of binary *
8 * 00000100 are omitted and stored */
unsigned int b : 3;
10 /* Last five bits 10111 of binary *
* 00110111 are omitted and stored */
12 unsigned int c : 5;
};
14

int main () {
16 struct bitfield bF ;
bF . a = 1; /* Binary equivalent to 00000001 */
18 bF . b = 4; /* Binary equivalent to 00000100 */
bF . c = 55; /* Binary equivalent to 00110111 */
20 printf ( " Size of bitfield struct is : % d \ n " , sizeof ( bF ) ) ;
printf ( " Bit field c has value : % d \ n " , bF . c ) ;
22 return 0;
}
✆✌

Size of bitfield struct is : 4
Bit field c has value : 23
✆✌
In following example, it is try to explain that how bit field data is stored in the memory
with help of pointer. The bitfield data is stored in memory created by struct from left to
right.

# include < stdio .h >
2

struct bitfield {
4 /* Last three bits 001 of binary *
* 00000001 are omitted and stored */
6 unsigned int a : 3;
/* Last three bits 100 of binary *
8 * 00000100 are omitted and stored */
unsigned int b : 3;
10 /* Last five bits 10111 of binary *
* 00110111 are omitted and stored */
118 Basic C

12 unsigned int c : 5;
};
14

int main () {
16 struct bitfield bF ;
bF . a = 1; /* Binary equivalent to 00000001 */
18 bF . b = 4; /* Binary equivalent to 00000100 */
bF . c = 55; /* Binary equivalent to 00110111 */
20 /* In memory the structure data *
* is stored as 10111 100 001 *
22 * read data without white spaces */
char * p ;
24 p = & bF ;
/* In memory the structure data is stored *
26 * as 10111 100 001*[ < - pointer is here ] *
* Above read data without white spaces */
28 p ++;
/* 101*[ < - pointer jumps here ] 11 100 001 */
30 printf ( " Size of bitfield struct is : % d \ n " , sizeof ( bF ) ) ;
/* Next 8 bit data is read from pointer location . *
32 * Here it is 00000 101 ( Binary equivalent to 5 */
printf ( " Pointer value is : % d \ n " , * p ) ;
34 return 0;
}
✆✌

Size of bitfield struct is : 4
Pointer value is : 5
✆✌
Following example is extended form of above example.

# include < stdio .h >
2

struct bitfield {
4 /* Last five bits 00001 of binary *
* 00000001 are omitted and stored */
6 unsigned int a : 5;
/* Last five bits 00100 of binary *
8 * 00000100 are omitted and stored */
unsigned int b : 5;
10 /* Last five bits 10111 of binary *
* 00110111 are omitted and stored */
12 unsigned int c : 5;
};
14

int main () {
16 struct bitfield bF ;
bF . a = 1; /* Binary equivalent to 00000001 */
18 bF . b = 4; /* Binary equivalent to 00000100 */
bF . c = 55; /* Binary equivalent to 00110111 */
20 /* In memory the structure data *
* is stored as 10111 00100 00001 */
1.5. PRECEDENCE OF OPERATORS 119

22 char * p ;
p = & bF ;
24 /* In memory the structure data is stored as *
* 10111 00100 00001*[ < - pointer is here ] *
26 * Above read data without white spaces */
p ++;
28 /* 10111 00*[ < - pointer jumps here ] 100 00001*
* Above read data without white spaces */
30 printf ( " Size of bitfield struct is : % d \ n " , sizeof ( bF ) ) ;
/* Next 8 bit data is read from pointer location . *
32 * Here it is 010111 00 ( Binary equivalent to 92) */
printf ( " Pointer value is : % d \ n " , * p ) ;
34 return 0;
}
✆✌

Size of bitfield struct is : 4
Pointer value is : 92
✆✌
Bitwise operators enable us to control the access and manipulation of individual bits of
a flag byte. these operators are very useful in controlling of bits of a flag register. For
example, in 8085 microprocessor, there are Sign, Zero, Reserve, Auxiliary Carry, Reserve,
Parity, Reserve and Carry bits. When all flag are high, then they form binary 11010101,
that is equal to decimal 213. If we want to change Zero bit to low from high, then we do
AND operation with the decimal 149, i.e. binary 10010101. It will change the Zero bit
low keeping other bits high.

11010101 ; decimal 213
2 10010101 ; decimal 149
- - - - - - - - - - - - -; AND operator
4 10010101 ; Zero bit is low
✆✌

1.5 Precedence of Operators


Precedence of operators is order of execution of C operators presence in an expression.
For example, in an expression
y = 5 + 3 − 4%2
We expect the result by addition of 5 + 3 = 8 which gives 8 − 4 = 4. The modulus of 4 by
2 as 4%2 = 0. Hence the final result is zero. But it is not true. Because addition can not
be performed before operation of modulus operator. Subtraction comes at last. It means
the expression can be written as

y = ((5 + 3) − (4%2))

On solving it, the final result is 8.



# include < stdio .h >
2

int main () {
120 Basic C

4 int y ;
y = 5 + 3 - 4 % 2;
6 printf ( " Result is : % d \ n " , y ) ;
return 0;
8 }
✆✌

Result is : 8
✆✌
To use the lower order operator before the upper order operator, parentheses are used.
Rewriting above example:

1 # include < stdio .h >

3 int main () {
int y ;
5 /* + operator is put above the \%*
* operator by using parentheses . */
7 y = (5 + 3 - 4) % 2;
printf ( " Result is : % d \ n " , y ) ;
9 return 0;
}
✆✌
In this example at first (5 + 3 − 4) is calculated which is 4 and its modulus with 2 is
4%2 = 0. Therefore the output of this example is

Result is : 0
✆✌

1.5.1 Precedence of Arithmetic Operators


Arithmetic problems are not solved from left to right in the sequence the expression
is written. But some rules are used. For example, parentheses are solved first, then
division, multiplication, addition and subtraction. Thus, arithmetic operators have some
precedence. Operators in order of decreasing precedence are given in table below.

Operators Associativity
() Left to right
+, – (unary) Right to left
*, /, % (modulo) Left to right
+, – (binary) Left to right
= Right to left

Table 1.18: Precedence of arithmetic operators from top to bottom in high to low order.

The precedence of the binary relational operators is less than that of the arithmetic
operators. This means, for example, x > y + 2 is same as x > (y + 2) and x = y > 2
1.5. PRECEDENCE OF OPERATORS 121

is same as x = (y > 2). It means, in an expression, order of evaluation of operators is


arithmetic operators, relational operators and assignment operators respectively.

1 # include < stdio .h >

3 int main () {
int x = 4 , y = 1;
5 /* x > y + 2 */
/* x > 1 + 2 */
7 /* x > 3 */
/* 4 > 3 ( true ) */
9 if ( x > y + 2) {
printf ( " Expression Passed . " ) ;
11 } else {
printf ( " Expression Failed . " ) ;
13 }
return 0;
15 }
✆✌

Expression Passed .
✆✌
Here is another example.

1 # include < stdio .h >
# include < stdlib .h >
3

int main ( int argc , char * argv [ ]) {


5 int y ;
/* Order of arithmetic operators *
7 * are / , * , + , -, =. So first 12*
* is divided by 5 and answer is *
9 * 2.4. 6 is multiply by 2.4 and *
* result is 14.4. It is added to *
11 * 20 and 10 is subtracted *
* The answer is 14.4+20 -10=24.4 */
13 y = 6 * 12 / 5 + 20 - 10;
/* In result only 24 is printed . *
15 * Decimal is truncated . */
printf ( " Expression result is % d \ n " , y ) ;
17 return 0;
}
✆✌

Expression result is 24
✆✌
In an expression, if there is a relational operator, then in the decreasing precedence of
operators, the relational operator comes above the assignment operator but below the
arithmetic operators.

1 # include < stdio .h >
# include < stdlib .h >
122 Basic C

int main ( int argc , char * argv [ ]) {


5 int y ;
/* First 6*12 and 5*20 are evaluated .*
7 *6*12 is 72 while 5*20 is 100. Now *
* relation operator < returns true *
9 * as 72 is less than 100. This true *
* value is assigned to variable y . */
11 y = 6 * 12 < 5 * 20;
printf ( " % d \ n " , y ) ;
13 return 0;
}
✆✌

1
✆✌

1.5.2 Precedence of Relational Operators


The operator precedence of relation & unary operators from top to bottom as high to low
order is given below.

Operators Associativity
() LR
–, +, ++, – –, sizeof (type), (all unary) RL
*, /, % (modulo) LR
+, – (binary) LR
<, >, <=, >= LR
==, != LR
= RL

From above table, it is seen that parentheses has highest priority among all the re-
lational and unary operators, after that, increment and unary operators. Arithmetic
operators and comparative operators has next. Assignment operator (=) has lowest pri-
ority. See the example below.

1 # include < stdio .h >

3 int main () {
int y =8;
5 /* First % operator is evaluated . As it has *
* highest priority . Next comes + and - and *
7 * in last , += operators . Using this order *
* the result of expression is y = 16. */
9 y += 5 + 3 - 4 % 2;
printf ( " Result is : % d \ n " , y ) ;
1.5. PRECEDENCE OF OPERATORS 123

11 return 0;
}
✆✌

Result is : 16
✆✌

1.5.3 Precedence of All Operators


In the following table, the precedence of all C operators are given. One should memorize
precedence of all operators if possible for quick troubleshooting and optimization of C
codes.

Operators Associativity
++ (postfix), – – (postfix), ( ), [ ], {}, . (dot), -> L-R
++ (prefix), – – (prefix), –, +, ˜, ! R-L
*, /, % (modulo) LR
+, – (both binary) L-R
<<, >> L-R
<, >, <=, >= L-R
==, != L-R
& L-R
ˆ L-R
| L-R
&& L-R
|| L-R
?: (conditional expression) R-L
=, *=, /=, %=, +=, –=, <<=, >>=, &=, |=, ˆ= R-L
, (comma operator) L-R

Table 1.19: Operator precedence of all C operators from top to bottom from high to low
order.

From above table, asterisk (*) has lower preference than square brackets ([ ], also
called array notation). This is why, to define the precedence order, parentheses are used.
Remember that, if comma used in an expression then C evaluates expression from left-
to-right direction, but the commas separating the arguments in a function call are not
comma operators.
124 Basic C

1.5.4 Precedence in Assignment


Precedence order is also obeyed in assigning a value to a variable. In example

1 # include < stdio .h >

3 int main () {
int a ;
5 a = 10 , 20 , 30;
printf ( " a =% d \ n " , a ) ;
7 a = (10 , 20 , 30) ;
printf ( " a =% d \ n " , a ) ;
9 return 0;
}
✆✌
in code line

a = 10 , 20 , 30;
✆✌
assigned value 10 to variable ‘a’ as ‘=’ has higher precedence over the ,(comma). Similarly
in code line

1 a = (10 , 20 , 30) ;
✆✌
assigned value 30 to variable ‘a’ as parentheses has highest precedence over the ,(comma)
and ‘=’. This is why, the output of above example is

a =10
a =30
✆✌

1.5.5 Unary & Binary Operators


In C, there are some unary operators and some binary operators. Unary operators require
only one operand, while binary operators need two operands. Now, if there are both,
unary and binary operators in same expression, then evaluation of operators is take place
according their precedence order. To understand it, we take following example

# include < stdio .h >
2 # include < stdlib .h >

4 int main ( int argc , char ** argv ) {


int i = 5;
6 int y ;
y = ++ i * ++ i * ++ i ;
8 printf ( " Result is % d . " , y ) ;
return 0;
10 }
✆✌

Result is 392.
✆✌
1.5. PRECEDENCE OF OPERATORS 125

Here, expression y has two operators, one ++ and other product (∗). In precedence order
of operators, increment operator (++) has higher precedence than product operator (∗).
An arithmetic expression is evaluated from left-to-right sequence according the precedence
order of operators. Sequence of evaluation of given expression is shown below:

1 y = ++ i * ++ i * ++ i ;
-------------------------------
3 1. y = ++ i // i =6
2. y = ++ i * // i =6
5 3. y = ++ i * ++ i // i =7
4. y = 7 * 7 * ++ i // i =7
7 5. y = 49 * ++ i // i =8
6. y = 49 * 8 = 392
✆✌
The evaluation is
First Step: + + i is evaluated and it makes i = 6.
Second Step: + + i∗ is not evaluated as product operator (∗) needs two operands
and it has only left side operand. It wait for its right side operands. Value of i has no
change, and it is i = 6.
Third Step: ++i∗++i is evaluated. Right side ++i to product operator makes i = 7.
There are two operands for product operator, hence arithmetic evaluation is performed.
Now, it is 7 ∗ 7 = 49. Remember, left and right side to product operator are variable i
hence both side the updated values are taken for product operation.
Rest of Steps: Now, + + i ∗ + + i ∗ + + i is evaluated. In this step, the expression is
like 49 ∗ + + i. There is of third + + i no effect on + + i ∗ + + i as it is already evaluated.
Therefore, final evaluation is 49 ∗ 8 = 392. This is final answer.

# include < stdio .h >
2 # include < stdlib .h >

4 int main ( int argc , char ** argv ) {


int i = 3;
6 int y ;
y = ++ i * ++ i + ++ i ;
8 printf ( " Result is % d . " , y ) ;
return 0;
10 }
✆✌
The initial program is now modified as given above. We have replace last product operator
with sum operator in the expression. The output of above program is

Result is 31.
✆✌
Here ++ has higher precedence than product operator (∗). Product operator has
higher precedence than sum operator (+). Product and sum operators are evaluated, after
their left and right operand’s evaluation. Steps of evaluation of arithmetic expression of
above program is given below:
126 Basic C


1 /* * has higher precedence than + */
y = ++ i * ++ i + ++ i ;
3 ---------------------------------------
1. y = ++ i // i =4
5 2. y = ++ i * // i =4
3. y = ++ i * ++ i // i =5
7 4. y = 5 * 5 + ++ i // i =6;
// On evaluation , product operator has
9 // higher precedence than sum operator
5. y = 25 + ++ i // i =6
11 6. y = 25 + 6 = 31
✆✌
Again, take the same program with modifications as given below. We have replace first
product operator with sum operator in the expression.

1 # include < stdio .h >
# include < stdlib .h >
3

int main ( int argc , char ** argv ) {


5 int i = 3;
int y ;
7 y = ++ i + ++ i * ++ i ;
printf ( " Result is % d . " , y ) ;
9 return 0;
}
✆✌
The output of above program is

Result is 42.
✆✌
It has different result than previous program. The evaluation of program is started
from left to right. Sum operator does not evaluated until product operator is not evaluated
due to precedence order. Steps of evaluation of expression of above program is given below:

1 /* * has higher precedence than + */
y = ++ i + ++ i * ++ i ;
3 --------------------------------------
1. y = ++ i // i =4
5 2. y = ++ i + // i =4
3. y = ++ i + ++ i // i =5;
7 /* Wait for Evaluation , product operator *
* has higher precedence than sum operator */
9 4. y = ++ i + ++ i * ++ i // i =6
5. y = ++ i + 6 * 6 // i =6 , use and increment
11 6. y = 6 + 36 = 42
✆✌

1.5.6 Associativity
The associativity of an operator is a property that determines how operators of the same
precedence are grouped in the absence of parentheses. Operators may be associative, left-
1.6. CONDITIONS 127

associative, right-associative or non-associative. The associativity and precedence of an


operator is a part of the definition of the programming language; different programming
languages may have different associativity and precedence for the same type of operator.
For example, aˆbˆc has left associativity as the expression is solved from left to right and
a=b=c to be interpreted as a=(b=c) and it has right associativity where both ‘a’ and ‘b’
to the value of ‘c’. A chained comparison like a<b<c is interpreted as (a<b) and (b<c),
it is not equivalent to either (a<b)<c or a<(b<c). It is called non-associativity.

1.6 Conditions
Conditions are the comparison statements those controls the execution of codes inside
the conditional blocks.

1.6.1 If Condition
if () provides a way to instruct the program to execute a block of code only if certain
conditions have been met, i.e. conditions given true result. In if condition of C language,
true is represented by ‘1’. The syntax of if () construct is

1 if ( /* conditions */ ) // if condition is true then
statement // execute the condition .
✆✌

# include < stdio .h >
2

int main () {
4 int b = 2 , c = 3;
if ( c > b ) {
6 printf ( " True -% d \ n " , c > b ) ; // true case
} else {
8 printf ( " False -% d \ n " , c > b ) ; // false case
}
10 return 0;
}
✆✌

True -1
✆✌
Note that, the equal comparison in C is ‘==’ and not ‘=’. The later symbol is assignment
operator that assigns the its right side value to left side variable and if assignment is
successful, it returns true. See the following simple example:

1 # include < stdio .h >

3 int main () {
int i = 10;
5 int j = 20;

7 /* In if statement , there is assignment not *


* comparison . This is why , if has true state . */
128 Basic C

9 if ( i = j )
printf ( " Is i equal to j ?\ n " ) ; // Printed .
11

/* Exact comparison . */
13 if ( i == j )
printf ( " i is perfectly equal to j .\ n " ) ; // Printed .
15 }
✆✌

Is i equal to j ?
i is perfectly equal to j .
✆✌

1.6.2 If-else Condition


if-else provides a way to instruct the program to execute a block of code only if certain
conditions have been met otherwise execute other block. All the conditions, except than
certain one defined for if, are true for else statement. This is why else has infinite numbers
of true conditions. The syntax of if-else construct is

if ( /* conditions */ ) // if condition is true then
2 statement one // execute the statement one .
else // otherwise if condition is false
4 statement two // execute the statement two .
✆✌
A simple example is

# include < stdio .h >
2

int main () {
4 int i = 10;
int j = 20;
6 if ( i == j )
printf ( " i is perfectly equal to j .\ n " ) ;
8 else
printf ( " i is not perfectly equal to j .\ n " ) ;
10 }
✆✌
If number of lines in a statement is more than one then these lines should be grouped
together by using curly braces i.e. { ..multi line statements.. }.

# include < stdio .h >
2

int main () {
4 int i = 10;
int j = 20;
6 if ( i == j ) { // Grouping by bracing for if condition
printf ( " i is perfectly equal to j .\ n " ) ; // Line No . 1
8 printf ( " Conditions are met .\ n " ) ; // Line No . 2
} else // Single line else condition is not braced here
10 printf ( " i is not perfectly equal to j .\ n " ) ;
1.6. CONDITIONS 129

}
✆✌
A short hand for of if-else condition is

1 int a =( b > c ) ? d : e ;
✆✌
Above statement is similar to the statement of “return d if b is greater than c else return
e”. if - else - if - else - if - else statement can be used successively. See the simple
example as given below:

1 # include < stdio .h >

3 int main () {
int i = 10;
5 int j = 20;
if ( i == j )
7 printf ( " i is perfectly equal to j .\ n " ) ;
else if ( i > j )
9 printf ( " i is greater than j .\ n " ) ;
else if ( i < j )
11 printf ( " i is lesser than j .\ n " ) ; // Printed .
else
13 printf ( " i is not equal to j .\ n " ) ;
return 0;
15 }
✆✌

i is lesser than j .
✆✌

1.6.3 If-else-if Case


Two if () conditions can be linked by else keyword. If-Else-If provides a way to instruct
the program to execute a block of code only if certain conditions have been met otherwise
execute other block conditionally. All the conditions, except than certain ones defined
for the first if, are true for else if statement. This is why, else if has infinite numbers of
true conditions. These infinite numbers of conditions are again checked for if statement
and the corresponding block is executed if certain conditions are met, otherwise these
conditions are skipped to next else if statement. The syntax of the linked if conditions
is

1 if ( /* condition 1 */ )
< expressions 1 >
3 else if ( /* condition 2 */ )
< expressions 2 >
5 else if ( /* condition 2 */ )
< expressions 3 >
✆✌
There may be end of this condition by else keyword or not. The example is
130 Basic C


# include < stdio .h >
2

void main () {
4 int i , j ;
i = 10;
6 j = 20;
if ( i == 10) { // print it
8 printf ( " i is % d \ n " , i ) ;
} else if ( j == 20) {
10 printf ( " j is % d \ n " , j ) ;
}
12 }
✆✌

i is 10
✆✌
Above example is modified so that the conditions are true for else if statement.

1 # include < stdio .h >

3 void main () {
int i , j ;
5 i = 11; // value is changed from 10 to 11
j = 20;
7 if ( i == 10) { // skip to next else - if
printf ( " i is % d \ n " , i ) ;
9 } else if ( j == 20) { // print it
printf ( " j is % d \ n " , j ) ;
11 }
}
✆✌

j is 20
✆✌
Above example is modified as shown below so that comparative conditions are neither
true for if () conditions or for else if condition. The program skips to both if () and else
if () and prints nothing in output console.

1 # include < stdio .h >

3 void main () {
int i , j ;
5 i = 11; // value is changed from 10 to 11
j = 21; // value is changed from 20 to 21
7 if ( i == 10) { // skip to next else - if
printf ( " i is % d \ n " , i ) ;
9 } else if ( j == 20) { // skip to next else - if
printf ( " j is % d \ n " , j ) ;
11 }
}
✆✌
1.6. CONDITIONS 131


✆✌
See the example below:

1 # include < stdio .h >

3 int main ( int argc , char * argv []) {


int i = 10;
5 if ( i == 10) { // First if case
printf ( " 1 : % d \ n " , i ) ;
7 }
if ( i == 11) { // Second if case
9 printf ( " 2 : % d \ n " , i ) ;
} else { // Corresponding else to second if
11 printf ( " 3 : % d \ n " , i ) ;
}
13 return 0;
}
✆✌
It result is

1 : 10
3 : 10
✆✌
There is only one true condition in the above program for variable ‘i’ but result
obtained twice. The reason is that the compiler checks the condition for first if case,
which is true and the result is obtained. Now the compiler checks the condition for
second if statement, which is false and the control is transferred to corresponding else
statement and program gives result again. If above program is rewritten as

# include < stdio .h >
2

int main ( int argc , char * argv []) {


4 int i = 10;
if ( i == 10) { // First if case , here true
6 printf ( " 1 : % d \ n " , i ) ;
} else if ( i == 11) { // on false , second if case
8 printf ( " 2 : % d \ n " , i ) ;
} else { // Corresponding else to second if
10 printf ( " 3 : % d \ n " , i ) ;
}
12 return 0;
}
✆✌
The result is

1 : 10
✆✌
Here from first if statement is true hence corresponding else-if statement is skipped
by the compiler and there is only one result.
132 Basic C

1.6.4 Switch & Case


Use of a long chain as if-else-if-else-if-else-if-else is very complex and less readable.
There’s a solution to it and we may use switch & case construct. A switch statement
is similar to if statement except that switch accepts single argument and compare it
with a range of defined values. It executes the block of statements for which case is
matched. if case is fixed executes only single block of statements. The basic syntax of
this construction is given below.

1 switch ( < case variable >) {
case 1:
3 < first statements >
break ;
5 case 2:
< second statements >
7 break ;
case 3:
9 < third statements >
break ;
11 default :
< default statements >
13 break ;
}
✆✌
Here default case is executed if none of the cases is matched with case variable value. If
switch statement has one case or default case then it behaves like if statement.

switch ( < case variable >) {
2 case 1:
< first statements >
4 break ;
} /* if like */
✆✌
Or

1 switch ( < case variable >) {
default :
3 < default statements >
break ;
5 } /* if like */
✆✌
Note that, the switch parameter takes only integer or character type values. It can not
be used with float type switch parameter. Following is working example

1 # include < stdio .h > /* fprintf */
# include < stdlib .h > /* malloc , free , exit */
3

int grade ;
5

int main ( void ) {


7 printf ( " Enter the grade : " ) ; // get the switch case value
1.6. CONDITIONS 133

scanf ( " % d " , & grade ) ; // recognise the supplied variable .


9

switch ( grade ) {
11 case 1:
printf ( " A \ n " ) ;
13 break ;
case 2:
15 printf ( " B \ n " ) ;
break ;
17 case 3:
printf ( " C \ n " ) ;
19 break ;
case 4:
21 printf ( " D \ n " ) ;
break ;
23 default : // if none of the above cases are matched .
printf ( " F \ n " ) ;
25 break ;
}
27 /* Exiting program */
exit ( EXIT_SUCCESS ) ;
29 }
✆✌
When program is run and input 1 is supplied, the output is

A
✆✌
Here operator ‘break’ plays an important role. If break operator is not used in block
of ‘case’ then all the successive blocks are executed successively. The reason behind is
that, ‘break’ inside the ‘case’ exits from the switch block from the current loop.

1 # include < stdio .h >

3 int main () {
int i = 0;
5 switch ( i ) {
/* for first loop , i =0.*
7 * Case 0 is executed . */
case 0: i += 2;
9 /* No following break operator . Switch *
* passes to the next case . Here i = 2 */
11 case 1: i += 2;
/* No following break operator . Switch *
13 * passes to the next case . Here i =4. */
case 5: i += 2;
15 /* No following break operator . Switch *
* passes to the next case . Here i =6. */
17 default :
i += 2; /* Here i =8. */
19 break ; /* Exit the switch */
}
134 Basic C

21 /* Print the 8 */
printf ( " % d \ t " , i ) ;
23 return 0;
}
✆✌

8
✆✌
Now, the break operator is inserted after case 1 in above example. The result is different
from the above example. It is so, because break operator let the exit of switch when case
is matched.

1 # include < stdio .h >

3 int main () {
int i = 0;
5 switch ( i ) {
/* for first loop , i =0.*
7 * Case 0 is executed . */
case 0: i += 2;
9 /* No following break operator . Switch *
* passes to the next case . Here i = 2 */
11 case 1: i += 2;
/* break operator exit switch *
13 * from current loop . Here i =4 */
break ;
15 case 5: i += 2; /* Never executed . */
default : /* Never executed . */
17 i += 2;
break ;
19 }
/* Print the 4 */
21 printf ( " % d \ t " , i ) ;
return 0;
23 }
✆✌

4
✆✌
For a given switch more than one similar case conditions can not be allowed. For example:

1 switch ( v ) {
case 0 : break ;
3 case 1 : break ;
case 0 : break ; // Error !! case 0 is redefine
5 }
✆✌
returns the compile time error as case ‘0’ is defined twice.
1.6. CONDITIONS 135

1.6.5 Goto Keyword


It is a jump operator. It transfers control unconditionally to another part of a program.
The statement used for goto operator is given below:

1 goto < identifier >;
✆✌
The identifier must be a label followed by a colon and statement. C language has a unary
&& operator that returns the address of a label. This address can be stored in a void*
variable type and may be used later in a goto instruction.

1 void * ptr = && JUMP1 ;

3 JUMP1 : printf ( " hi " ) ;


goto * ptr ;
✆✌

# include < stdio .h >
2 # include < stdlib .h >

4 int main ( void ) {


int i = 0;
6 LOOP :
if ( i == 100) {
8 exit (0) ;
}
10 while ( i < 100) {
i ++;
12 if ( i % 2 == 0)
goto JUMP1 ;
14 else
goto JUMP2 ;
16 }

18 JUMP1 :
printf ( " % d is Even Number \ n " , i ) ;
20 goto LOOP ;

22 JUMP2 :
printf ( " % d is Odd Number \ n " , i ) ;
24 goto LOOP ;
return EXIT_SUCCESS ;
26 }
✆✌

1.6.6 Break Keyword


break keyword is used to break a loop or continuous operation. It is always used within
loop and its use outside the loop cause compile time error.

# include < stdio .h >
2
136 Basic C

int ix ;
4 int main ( void ) {
for ( ix = 1; ix <= 10; ix ++) {
6 /* First hello , world ! */
printf ( " % d Hello , world ! " , ix ) ;
8 break ;
}
10 return 0;
}
✆✌
The output of above program is

1 Hello , world !
✆✌
In above example, loop is iterated only once. During the first loop of for block, break
stops the further execution of for loop. In a simple program we can use blank line for
offset to make the programming code readable.

1.7 Iteration
Iteration is a process in which code statements are executed more than once. For example,
to print a line ten times, either the line is written ten times one after another or a loop
is used to print the line ten times. Most common iteration/loop functions are for and
while.

1.7.1 For Loop


The syntax of for loop is

1 for ( initializat io n ; test ; increment ) {
/* code */
3 }
✆✌
The function for, first initializes the variable and then conditions are checked according
the ‘test’. If initialized value of the variable passed the ‘test’, expressions or codes in-
side the function body are executed. After each successful execution of loop, variable is
incremented according the relation of ‘increment’. See example given below:

1 # include < stdio .h >

3 main ( void ) {
int a , b ;
5 b = 15;
for ( a = 10; a < b ; a ++) {
7 printf ( " The number a is % d .\ n " , a ) ;
}
9 }
✆✌
The output is
1.7. ITERATION 137


The number a is 10.
The number a is 11.
The number a is 12.
The number a is 13.
The number a is 14.
✆✌
The declaration cum initialization of variable inside the for parentheses is allowed
only in C99 or C11 standards. All C standards older than C99 need pre-declaration of
variable before they are initialized inside for parentheses.

1 for ( int initializat io n ; test ; increment ) {
/* code */
3 }
✆✌
Example of above for syntax is given below:

1 # include < stdio .h >

3 main ( void ) {
int b = 15;
5 for ( int a = 10; a < b ; a ++) { /* C99 & C11 Standards . */
printf ( " The number a is % d .\ n " , a ) ;
7 }
}
✆✌
The value of variable may also be changed from the function body. See example below:

# include < stdio .h >
2

int main () {
4 int i ;
for ( i = 1; i < 10; i += 2) {
6 if ( i == 3)
i - -;
8 printf ( " %d , " , i ) ;
}
10 return 0;
}
✆✌

1, 2, 4, 6, 8,
✆✌
The initialization statement is executed exactly once. It is used to assign an initial value
to some variable. The test expression is evaluated each time before the code in the for
loop executes. If this expression evaluates as 0 (false), the loop is not (re)enter into the
for loop. And execution of program carry on to the code immediately following the for
loop. If the expression is non-zero (ie true), the loop is (re)enter inside the for loop.
After each iteration of the loop, the increment statement is executed. In last iteration,
required conditions are not satisfied and loop exits after execution of increment. This is
often used to increment the loop index.
138 Basic C


1 # include < stdio .h >

3 int main ( int argc , char ** argv ) {


int i ;
5 for ( i =0; i <5; i ++) ; // only increment index , i =5
printf ( " i is % d . " , i ) ;
7 return 0;
}
✆✌

i is 5.
✆✌
An infinite loop is executed if for is defined as shown below.

1 for (;;) {
/* statements / codes */
3 }
✆✌
Multiple initialization can be used by separating them by comma.

1 for ( initializat io n one , /* First var initialized */
initializat io n two ; /* Second var initialized */
3 test of initializers ; /* Test the condition of variables */
increment one , /* Increment of first variable */
5 increment two ) { /* Increment of second variable */

7 /* expressions / statements / codes */

9 }
✆✌

1 # include < stdio .h >
# include < stdlib .h >
3

int main ( void ) {


5 int i , j ;
for ( i = 1 , /* First var initialized */
7 j = 2; /* Second var initialized */
i < 5 , /* Test first variable */
9 /* Here comma mean OR */
j < 11; /* Test second variable */
11 i ++ , /* Increment of first variable */
j = j + 2) /* Increment of second variable */ {
13 printf ( " Product of i =% d & j =% d is % d \ n " , i , j , i * j ) ;
}
15 return 0;
}
✆✌

Product of i =1 & j =2 is 2
Product of i =2 & j =4 is 8
Product of i =3 & j =6 is 18
1.7. ITERATION 139

Product of i =4 & j =8 is 32
Product of i =5 & j =10 is 50
✆✌

1 # include < stdio .h >
# include < stdlib .h >
3

int main ( void ) {


5 int i , j ;
for ( i = 1 , /* First var initialized */
7 j = 2; /* Second var initialized */
i < 5 /* Test first variable */
9 && /* AND test for i and j */
j < 11; /* Test second variable */
11 i ++ , /* Increment of first variable */
j = j + 2) /* Increment of second variable */ {
13 printf ( " Product of i =% d & j =% d is % d \ n " , i , j , i * j ) ;
}
15 return 0;
}
✆✌

Product of i =1 & j =2 is 2
Product of i =2 & j =4 is 8
Product of i =3 & j =6 is 18
Product of i =4 & j =8 is 32
✆✌
An example containing the conditional for is

# include < stdio .h >
2

main ( void ) {
4 int a , b ;
a = 10 , b = 15;
6 for ( a = 10; a < 30 && b != a ; a ++) {
printf ( " The number a is % d .\ n " , a ) ;
8 }
}
✆✌
The output is

The number a is 10.
The number a is 11.
The number a is 12.
The number a is 13.
The number a is 14.
✆✌
There is an example of finding prime numbers by using for loops.

1 /* For the square root function sqrt () */
# include < math .h >
3 # include < stdio .h >
140 Basic C

5 int is_prime ( int n ) ;

7 int main () {
/* Enter a number . Only integer . */
9 printf ( " Write an integer : " ) ;
/* Scan the integer . */
11 int var ;
scanf ( " % d " , & var ) ;
13 /* Defining output */
if ( is_prime ( var ) == 1) {
15 printf ( " A prime \ n " ) ;
} else {
17 printf ( " Not a prime \ n " ) ;
}
19 return 1;
}
21

int is_prime ( int n ) {


23 int x ;
int sq = sqrt ( n ) + 1;
25 /* Checking the trivial cases first */
if ( n < 2)
27 return 0;
if ( n == 2 || n == 3)
29 return 1;
/* Check whether n is divisible by 2 or is an *
31 * odd number between 3 and square root of n . */
if ( n % 2 == 0)
33 return 0;
for ( x = 3; x <= sq ; x += 2) {
35 if ( n % x == 0)
return 0;
37 }

39 return 1;
}
✆✌

Write an integer : 12
Not a prime
✆✌
Variables used in for control function, can also be assigned a character code if a character
is enclosed inside single quote. In following example, 26 English characters in lower case
form are printed by using for loop.

# include < stdio .h >
2

int main ( void ) {


4 int i ;
printf ( " 26 english letters : \ n " ) ;
6 for ( i = ’a ’; i < ( ’a ’ + 26) ; i ++) {
1.7. ITERATION 141

printf ( " %3 d = % c ,\ t " , i , i ) ;


8 if (( i - ’a ’ + 1) % 5 == 0)
printf ( " \ n " ) ;
10 }
return 0;
12 }
✆✌

97 = a, 98 = b, 99 = c, 100 = d, 101 = e,
102 = f, 103 = g, 104 = h, 105 = i, 106 = j,
107 = k, 108 = l, 109 = m, 110 = n, 111 = o,
112 = p, 113 = q, 114 = r, 115 = s, 116 = t,
117 = u, 118 = v, 119 = w, 120 = x, 121 = y,
122 = z,
✆✌

1.7.2 While Loop


A while() loop is the most basic type of loop. It will run as long as the condition returns
non-zero (ie true) value. At false state, while loop exits.

# include < stdio .h >
2 # include < string .h >
# include < stdlib .h >
4 int a = 1;

6 int main ( void ) {


/* Loops until the break statement in the loop is executed */
8 while (42) {
printf ( " : - > a is % d \ n " , a ) ;
10 a = a * 2;
if ( a > 100) {
12 break ;
} else if ( a == 64) {
14 /* Immediately restarts at while , skips next step */
continue ;
16 }
printf ( " : - > a is NOT 64\ n " ) ;
18 }
exit ( EXIT_SUCCESS ) ;
20 }
✆✌

:-> a is 1
:-> a is NOT 16
:-> a is 2
:-> a is NOT 16
:-> a is 4
:-> a is NOT 16
:-> a is 8
:-> a is 16
✆✌
142 Basic C

1.7.3 For As While


The syntax of for loop as

for (; <test > ; )
✆✌
is similar to the while loop

1 while ( < test >)
✆✌
Following is an example which shows that for loop is similar to the while loop.

1 # include < stdio .h >

3 int main () {
int i = 0;
5 for (; i < 5;) {
printf ( " % d \ t " , i ) ;
7 i ++;
}
9 printf ( " \ n " ) ;
int j = 0;
11 while ( j < 5) {
printf ( " % d \ t " , j ) ;
13 j ++;
}
15 printf ( " \ n " ) ;
return 0;
17 }
✆✌

0 1 2 3 4
0 1 2 3 4
✆✌

1.7.4 Do While
do-while loop is similar to the while loop except at least one loop is executed before the
conditional test is checked. So while loop is used where execution of loops is required
after test and do-while loop is used where at least one loop is must before conditional
check. This loop has syntax like

do {
2 < loop body >
} while ( < conditional check >)
✆✌
The comparative example of while and do-while loops is given below:

1 # include < stdio .h >

3 int main ( void ) {


/* do - while loop */
1.8. STRINGS 143

5 int i = 0;
printf ( " Do - while Loop : \ n " ) ;
7 do { /* One output loop */
printf ( " i = % d \ n " , i ) ;
9 i ++;
} while ( i < 0) ;
11 /* while loop */
i = 0;
13 printf ( " \ nWhile Loop : \ n " ) ;
while ( i < 0) { /* No outputs */
15 printf ( " i = % d \ n " , i ) ;
i ++;
17 }
return 0;
19 }
✆✌

Do - while Loop :
i = 0

While Loop :
✆✌

1.8 Strings
The string constant “x” is not the same as the character constant i.e. ‘x’. One difference
is that ‘x’ is a basic type (char), but “x” is a derived type, an array of char. A second
difference is that “x” really consists of two characters, ‘x’ and ‘\0’, the null character.

1 char ch = ’ x ’; // valid assignment
char str [2]= " x " ; // valid assignment
✆✌

ch x str x \0

Again, a chacter inside the single quote is integer type while same character inside double
quote is of char * type. It is implementation method that whether string variable may
or may not be assigned single quote strings.

char str [2]= ’x ’; // Valid assignment with warning as ’x ’ is int type
2 char * str = ’x ’ // Valid assignment with warning as ’x ’ is int type
✆✌
String with single quote has special meaning. See the example given below:

# include < stdio .h >
2

int main () {
4 char * ch = ’ 1234 ’;
printf ( " % d " , ch ) ;
144 Basic C

6 return 0;
}
✆✌

825373492
✆✌
Here, each character is converted into its equivalent char code and then char codes are
placed in sequential memory bytes. Note that there is no null terminator, hence there is
no end of this string. Compiler will reach beyond the limit of string when read it. So,
when we dereference this string variable as string, error of segmentation fault is returned
by the compiler. Again, when we dereference the string variable as integer, it returns
the decimal number created from first four memory bytes started from the address of
string variable. A string in C is merely an array of characters. The length of a string
is determined by a terminating null character: ‘\0’. So, a string with the contents, say,
“abc” has four characters: ‘a’, ‘b’, ‘c’, and the terminating null character ‘\0’.

1 char str [4]= " abc " ;
✆✌

str a b c \0

In C, string constants (literals) are surrounded by double quotes (“...”), e.g. “Hello
world!” and are compiled to an array of the specified char values with an additional null
terminating character (0-valued) code to mark the end of the string. Note that, if the
size of character array is larger than the size of string stored, the remaining bytes after
null terminator are part of the array but not the part of string.

1 char str [7]= " abc " ;
✆✌

str a b c \0 ? ? ?

The type of a string constant is char *. String literals may not directly in the source
code contain embedded newlines or other control characters, or some other characters of
special meaning in string. To include such characters in a string, the backslash escapes
may be used, like this:
1.8. STRINGS 145

Escape Meaning
\ Literal backslash
\" Double quote
\’ Single quote
\n Newline (line feed)
\r Carriage return
\b Backspace
\t Horizontal tab
\f Form feed
\a Alert (bell)
\v Vertical tab
\? Question mark (used to escape trigraphs)
\nnn Character with octal value nnn
\xhh Character with hexadecimal value hh

Table 1.20: Escape characters in C.

A simple example is

1 # include < stdio .h >

3 int main () {
int i ;
5 while ( i < 10) {
printf ( " % i .\ n \ a \ v " ,i ) ;
7 i ++;
}
9 return (0) ;
}
✆✌
An equivalent hexadecimal value of a charcode as hexadecimal escape character format
(\xhh) can be put in the output console of C by using printf function.

# include < stdio .h >
2

int main ( void ) {


4 char * s = " \ x41 \ x42 \ x54 " ;
printf ( " s = % s \ n " , s ) ;
6 return 0;
}
✆✌

s = ABT
✆✌
146 Basic C

Multi-bytes hexadecimal character string can be assigned to a char type variable by using
‘wchar t’ keyword. The value assigned to the variable must be preceded with character
‘L’ as shown in the following example.

1 # include < stdio .h >
# include < wchar .h >
3

int main ( void ) {


5 wchar_t * s = L " \ x4142 \ x4344 " ;
printf ( " s = % s \ n " , s ) ;
7 return 0;
}
✆✌

s = BADC
✆✌

1.8.1 Character Encoding


char and wchar t are not specified in the C standards. Except that the value ‘0×00’ and
‘0×0000’ specify the end of the string and not a character. Input and output codes are
directly affected by the character encoding. Other code should not be too affected. The
editor should also be able to handle the encoding if strings shall be able to written in the
source code. There are three major types of encoding:
1. One byte per character. Normally based on ASCII. There is a limit of 255 different
characters plus the zero termination character.
2. Variable length character strings, which allows many more than 255 different char-
acters. Such strings are written as normal char-based arrays. These encoding are
normally ASCII-based and examples are UTF-8 or Shift JIS.

1.8.2 String Literal In Expression


When a string appears in an expression it is considered as a pointer and indices or
indirection rules can be applied on it. See the example given below:

1 # include < stdio .h >

3 int main ( int argc , char ** argv ) {


printf ( " % d \ n " , " xyz " ) ; // pointer
5 printf ( " % d \ n " , * " xyz " ) ; // pointer to characters
printf ( " % d \ n " , ( " xyz " [1] + 1) ) ; // sum of ’y ’ and 1
7 return 0;
}
✆✌

4202528
120
122
✆✌
1.8. STRINGS 147

In first case, string literal represents to a pointer and return the address to which this
string literal is pointing. In second and third case, string literals are converted into
“pointer to character”, therefore it returns the value of first character of what it points,
i.e. ‘x’. In third case, sum of char value of character at indices 1 (i.e. ‘y’), and one is
returned.

1.8.3 String Functions


The nine most commonly used functions in the string library are

strcat
This function concatenate the string source object with destination object. The size of
destination object shall be sufficiently large to hold all the supplied strings from source
object. If size of string variable is deficient to space, an overflow error occurs. The
synopsis of the strcat function is

1 char * strcat ( char * restrict s1 , const char * restrict s2 ) ;
✆✌

strcat(str1, str2)
str1 a b c \0

str2 A B C \0

After catenation of the strings, ‘str1’ variable points to the strings as shown below:

str1 a b c A B C \0

It is recommended that strncat () or strlcat () should be used instead of strcat(), in


order to avoid buffer overflow. A simple example is

1 # include < stdio .h >
# include < string .h >
3

int main () {
5 /* initialize a char variable */
char str [80];
7 /* copy string The to variable . */
strcpy ( str , " The " ) ;
9 /* concate the string India with The */
strcat ( str , " India " ) ;
11 strcat ( str , " is " ) ;
strcat ( str , " developing . " ) ;
148 Basic C

13 /* put output at the console */


puts ( str ) ;
15 return 0;
}
✆✌

The India is developing .
✆✌

strchr
The synopsis of the strchr function is

1 char * strchr ( const char *s , int c ) ;
✆✌
The strchr() function shall locate the first occurrence of ‘c’ (converted to a char) in the
string pointed-by ‘s’. A simple example is

1 # include < stdio .h >
# include < string .h >
3

int main () {
5 char str [ ] = " This is my country " ;
char * pch ;
7 printf ( " Geting char s in \"% s \".\ n " , str ) ;
pch = strchr ( str , ’ s ’) ;
9 while ( pch != NULL ) {
printf ( " ’s ’ char is at position % d \ n " , pch - str + 1) ;
11 pch = strchr ( pch + 1 , ’s ’) ;
}
13 return 0;
}
✆✌

Geting char s in " This is my country ".
’s ’ char is at position 4
’s ’ char is at position 7
✆✌

strcmp
The strcmp synopsis is

1 int strcmp ( const char * s1 , const char * s2 ) ;
✆✌
A rudimentary form of string comparison is done with the strcmp() function. It takes
two strings as arguments and returns a negative value if the first is lexographically less
than the second, a value greater than zero if the first is lexographically greater than the
second, or zero if the two strings are equal. The comparison is done by comparing the
coded (ascii) value of the characters in character-by-character manner. A simple example
is
1.8. STRINGS 149


1 # include < stdio .h >
# include < string .h >
3

int main () {
5 char Key [ ] = " apple " ;
char Input [80];
7 do {
printf ( " Guess my favourite fruit ? " ) ;
9 gets ( Input ) ;
} while ( strcmp ( Key , Input ) != 0) ;
11 puts ( " Correct answer ! " ) ;
return 0;
13 }
✆✌

Guess my favourite fruit ? apple
Correct answer !
✆✌
This is another example in which two strings are compared without using strcmp() func-
tion.

# include < stdio .h >
2

int Compare_Ma in _ Su b ( char * , char *) ;


4

int main () {
6 char MainStr [100] , SubStr [100] , CnF ;

8 printf ( " Enter Main string : \ n " ) ;


gets ( MainStr ) ;
10

printf ( " Enter Sub string : \ n " ) ;


12 gets ( SubStr ) ;

14 CnF = Compare_Mai n_ S ub ( MainStr , SubStr ) ;

16 if ( CnF == 0)
printf ( " Both strings are same .\ n " ) ;
18 else
printf ( " Entered strings are not equal .\ n " ) ;
20

return 0;
22 }

24 int Compare_Ma in _ Su b ( char * MainStr , char * SubStr ) {


while (* MainStr == * SubStr ) {
26 if (* MainStr == ’ \0 ’ || * SubStr == ’ \0 ’)
break ;
28

MainStr ++;
30 SubStr ++;
150 Basic C

}
32 if (* MainStr == ’ \0 ’ && * SubStr == ’ \0 ’)
return 0;
34 else
return -1;
36 }
✆✌

Enter Main string : a
Enter Sub string : a
Both strings are same .
✆✌
C has no dedicated boolean procedure. Hence in string comparison, return value is 0 on
true and other value on false. In case of != comparison C fails to check condition. See
example

1 # include < stdio .h >

3 int main () {
char c [2];
5 printf ( " Type ’e ’ for encrypt & ’ d ’ for decrypt : " ) ;
scanf ( " % s " , c ) ;
7 if ( strcmp (c , " e " ) != 0 || strcmp (c , " d " ) != 0) {
printf ( " Unknown procedure .\ n " ) ;
9 }
return 0;
11 }
✆✌

Type ’e ’ for encrypt & ’d ’ for decrypt : f
Unknown procedure .
✆✌

Type ’e ’ for encrypt & ’d ’ for decrypt : e
Unknown procedure .
✆✌
In these type of problems, try to use the false statement.

# include < stdio .h >
2

int main () {
4 char c [2];
printf ( " Type ’e ’ for encrypt & ’ d ’ for decrypt : " ) ;
6 scanf ( " % s " , c ) ;
if ( strcmp (c , " e " ) == 0 || strcmp (c , " d " ) == 0) {
8 } else {
printf ( " Unknown procedure .\ n " ) ;
10 }
return 0;
12 }
✆✌
1.8. STRINGS 151


Type ’e ’ for encrypt & ’d ’ for decrypt : e
✆✌

Type ’e ’ for encrypt & ’d ’ for decrypt : f
Unknown procedure .
✆✌

strcpy
This function copies the string from source into destination. The size of the destination
object shall be sufficiently large to hold the source string. If size of destination object is
deficient of space, an overflow error occurs. The syntax of strcpy() is

char * strcpy ( char * restrict dest , \
2 const char * restrict src ) ;
✆✌
Note, source of strcpy should be string. It is recommended that strncpy() should be used
instead of strcpy(), to avoid buffer overflow. A simple example is

# include < stdio .h >
2 # include < string .h >

4 int main () {
/* initialize a char variable */
6 char str [80];
/* copy string The to variable . */
8 strcpy ( str , " The " ) ;
/* concate the string India with The */
10 strcat ( str , " India " ) ;
strcat ( str , " is " ) ;
12 strcat ( str , " developing . " ) ;
/* put output at the console */
14 puts ( str ) ;
return 0;
16 }
✆✌

The India is developing .
✆✌
An example which copies the contents of one array into other array without using strcpy()
function is given below. In this example, one by one character of array ‘strA’ are copied
into array ‘strB’. When array ‘strA’ encounters the null character, copying is halted.

1 # include < stdio .h >

3 int main () {
char strA [50] , strB [50];
5 int i ;
printf ( " \ nEnter string s1 : " ) ;
7 scanf ( " % s " , strA ) ;
/* Copy one by one character into strB . */
152 Basic C

9 for ( i = 0; strA [ i ] != ’ \0 ’; i ++) {


strB [ i ] = strA [ i ];
11 }
/* Add null character to strB at the end . */
13 strB [ i ] = ’ \0 ’;
printf ( " \ nString s2 : % s " , strB ) ;
15 return 0;
}
✆✌
Following is a strcpy() example that is used to trim the white spaces from the left and
right hand side of a string.

# include < stdio .h >
2 # include < string .h >
# include < ctype .h >
4

/* Trimming leading and trailing white spaces . */


6 char * trim ( char * s ) {
/* Initialize start , end pointers */
8 char * s1 = s , * s2 = & s [ strlen ( s ) - 1];

10 /* If last char is a white space and there *


* is a previous char that is also a white *
12 * space then reduce the pointer by one *
* for each white space . */
14 while (( isspace (* s2 ) ) && ( s2 >= s1 ) )
s2 - -;
16 /* Finally we find the pointer value for *
* last character other than a white space . */
18

/* Add end of line . */


20 *( s2 + 1) = ’ \0 ’;

22 /* If first char is a white space and there *


* is next char that is also a white space *
24 * then increase the pointer position by *
* one for each white space . */
26 while (( isspace (* s1 ) ) && ( s1 < s2 ) )
s1 ++;
28

/* Copy rest of string to s */


30 strcpy (s , s1 ) ;
return s ;
32 }

34 int main ( int argc , char * argv [ ]) {


char * s ;
36 char string [100] = " 1 arun2 ";
printf ( " The original string is :% s :\ n " , string ) ;
38 s = trim ( string ) ;
printf ( " The trimmed string is :% s :\ n " , s ) ;
1.8. STRINGS 153

40 return 0;
}
✆✌

The original string is : 1 arun 2 :
The trimmed string is :1 arun 2:
✆✌

strlen
Synopsis of strlen() function is

size _ t strlen ( const char * s ) ;
✆✌
The strlen() function shall compute the number of bytes in the string to which ‘s’ points,
not including the terminating null byte. It returns the number of bytes in the string. No
value is used to indicate an error. A simple example is

1 # include < stdio .h >
# include < string .h >
3

int main () {
5 char Input [256];
printf ( " Enter a string : " ) ;
7 gets ( Input ) ;
printf ( " The string length is % u characters long .\ n " ,
9 ( unsigned ) strlen ( Input ) ) ;
return 0;
11 }
✆✌

Enter a string : a
The string length is 1 characters long .
✆✌
strlen() counts only those cells in which string or character is stored. The counting of
strlen() is stopped when, it encountered the cell of null character. We can used several
methods to find the string length without using strlen function.

# include < stdio .h >
2 # include < stdlib .h >

4 int main ( void ) {


int n = 0 , c ;
6 /* get string to be counted */
printf ( " Enter the string : " ) ;
8 while (( c = getchar () ) != ’\ n ’) {
n ++;
10 }
printf ( " The string length is % d .\ n " , n ) ;
12 return 0;
}
✆✌
154 Basic C


Enter the string : arun kumar
The string length is 10.
✆✌
A new example that uses array and strlen() function to get reverse of the supplied string.
Actually in this example, strlen() function is used to get the length of the string. After
that the characters of the string are printed in reverse order.

# include < stdio .h >
2 # include < stdlib .h >

4 int main ( void ) {


char rs [1000]; // string to reversed .
6 /* get string to be reversed */
printf ( " Enter the string to be reversed : " ) ;
8 scanf ( " % s " , rs ) ;
printf ( " The reversed string is : " ) ;
10 /* While array is not triggered with space */
int n = strlen ( rs ) ;
12 while ( n > 0) {
printf ( " % c " , rs [ n - 1]) ;
14 n - -;
}
16 return 0;
}
✆✌

Enter the string to be reversed : arun
The reversed string is : nura
✆✌
In following example, classical method is used to find the length of a string. In this
example, we count the characters in a string until a null terminating character is not
obtained. After each counting, counter is increased by one. At last the counting value is
the actual length of the string.

# include < stdio .h >
2

int main ( void ) {


4 char name [ ] = " NAME arun kr " ;
int i = 0;
6 while ( name [ i ] != NULL )
i ++;
8 printf ( " The length of string " % s " is % d . " , name , i ) ;
return 0;
10 }
✆✌

The length of string " NAME arun kr " is 12.
✆✌
The following example is rewritten in which string pointer is passed to a function where
string length is computed. The string length is returned to the main function and printed
in output console.
1.8. STRINGS 155


1 # include < stdio .h >

3 int StrLen ( char * str ) {


int i = 0;
5 while ( str [ i ] != ’ \0 ’) {
i ++;
7 }
return i ;
9 }

11 int main () {
char str [ ] = " This is my string . " ;
13 int i ;
i = StrLen ( str ) ;
15 printf ( " The length of string is % d .\ n " , i ) ;
return 0;
17 }
✆✌

The length of string is 18.
✆✌
The memory used by given string may also be retrieve by using keyword ‘sizeof’ as shown
in example below.

1 # include < stdio .h >
# include < string .h > /* provides strlen () prototype */
3 # define PRAISE " Hi ! "

5 int main ( void ) {


char name [40];
7 printf ( " What ’s your name ?\ n " ) ;
scanf ( " % s " , name ) ;
9 printf ( " Hello , % s . % s \ n " , name , PRAISE ) ;
printf ( " Name has % d letters & occupies % d memory cells .\ n " ,
11 strlen ( name ) , sizeof name ) ;
printf ( " The praise has % d letters " , strlen ( PRAISE ) ) ;
13 printf ( " and occupies % d memory cells .\ n " , sizeof PRAISE ) ;
return 0;
15 }
✆✌

What ’ s your name ?
Arun
Hello , Arun . Hi !
Name has 4 letters & occupies 40 memory cells .
The praise has 3 letters and occupies 4 memory cells .
✆✌

strncat
strncat () function concatenate specific number of characters into destination from the
source. Synopsis of this function is
156 Basic C


1 char * strncat ( char * s1 , const char * s2 , size_t n ) ;
✆✌
The strncat () function shall not append more than ‘n’ bytes. A simple example is

1 # include < stdio .h >

3 int main () {
char str1 [20];
5 char str2 [20];

7 strcpy ( str1 , " Hello " ) ;


strcpy ( str2 , " Worldddddddd d " ) ;
9

printf ( " Concatenated string is : % s \ n " , strncat ( str1 , str2 , 4) ) ;


11 printf ( " Final string is : % s \ n " , str1 ) ;

13 return 0;
}
✆✌

Concatenated string is : HelloWorl
Final string is : HelloWorl
✆✌

strncmp
The strncmp function syntax is

int strncmp ( const char * s1 , const char * s2 , size_t n ) ;
✆✌
The strncmp() function shall compare not more than n bytes (bytes that follow a null
byte are not compared) from the array pointed-by ‘s1’ into the array pointed-by ‘s2’. The
sign of a non-zero return value is determined by the sign of the difference between the
values of the first pair of bytes (both interpreted as type unsigned char) that differ in
the strings being compared. See strcmp() for an explanation of the return value. This
function is as useful in comparisons, as the strcmp function is. A simple example is

1 # include < stdio .h >
# include < string .h >
3

int main () {
5 if ( strncmp ( " arun " , " Arun " , 2) ==0) {
printf ( " Two strings are equal . " ) ;
7 } else {
printf ( " Two strings are not equal . " ) ;
9 }
return (0) ;
11 }
✆✌

Two strings are not equal .
✆✌
1.8. STRINGS 157

strncpy
The syntax of strncpy() function is

1 char * strncpy ( char * s1 , const char * s2 , size_t n ) ;
✆✌
The strncpy() function shall copy not more than ‘n’ bytes (bytes that follow a null byte
are not copied) from the array pointed-by ‘s2’ into the array pointed-by ‘s1’. A simple
example is

1 # include < stdio .h >
# include < string .h >
3

int main () {
5 /* initialize an experimental string */
char str [ ] = " This is a simple string " ;
7 char * pch ;
/* get first occurace of simple */
9 pch = strstr ( str , " simple " ) ;
/* copy NAGPUR from the point of simple upto two places . */
11 strncpy ( pch , " NAGPUR " , 2) ;
/* copy NAGPUR from the point of simple upto four places . */
13 strncpy ( pch , " NAGPUR " , 4) ;
puts ( str ) ;
15 /* copy NAGPUR from the point of simple upto six places . */
strncpy ( pch , " NAGPUR " , 6) ;
17 puts ( str ) ;
return 0;
19 }
✆✌

This is a NAmple string
This is a NAGPle string
This is a NAGPUR string
✆✌
In the above program, line

1 strncpy ( pch , " NAGPUR " , 2) ;
✆✌
copied first two characters from the “NAGPUR” at 11th and 12th place of the string ‘str’
as shown below:
strncpy(pch, “NAGPUR”, 2)
s i m p l e s

N A G P U R \0

Similarly, in the above program, line



1 strncpy ( pch , " NAGPUR " , 6) ;
✆✌
158 Basic C

copied first six characters from the “NAGPUR” into ‘str’ from 11th to 16th place of the
string ‘str’ as shown below:
strncpy(pch, “NAGPUR”, 6)
s i m p l e s

N A G P U R \0

During the copying of strings, size of strings should be clearly defined, otherwise the
actual string may terminate shortly as null terminator is added within the actual string
as shown in the following example.

1 # include < stdio .h >
# include < string .h >
3

int main () {
5 /* initialize an experimental string */
char str [ ] = " This is a simple string " ;
7 char * pch ;
/* get first occurace of simple */
9 pch = strstr ( str , " simple " ) ;
/* copy NAGPUR from the point of simple upto seven places . */
11 strncpy ( pch , " NAGPUR " , 7) ;
puts ( str ) ;
13 return 0;
}
✆✌

This is a NAGPUR
✆✌

strncpy(pch, “NAGPUR”, 7)
s i m p l e s

N A G P U R \0

strrchr
The strrchr () function searches string for the last occurrence of a character. The null
character that represents to the termination of string, is also included in the search. The
prototype of strrchr () function is

1 char * strrchr ( const char *s , int c ) ;
✆✌
strrchr is similar to strchr(), except the string is searched right to left. A simple example
is
1.8. STRINGS 159


1 # include < stdio .h >

3 int main () {
char * s ;
5 char buf [ ] = " This is a testing " ;

7 s = strrchr ( buf , ’t ’) ;

9 if ( s != NULL )
printf ( " found a ’t ’ at % s \ n " , s ) ;
11

return 0;
13 }
✆✌

found a ’t ’ at ting
✆✌
Here is another example that returns the position in a string where a delimiter is found.

1 # include < stdio .h >
# include < string .h >
3

int main () {
5 char str [ ] = " This is my string " ;
char match [ ] = " i " ;
7 int i ;
int c = 0;
9 for ( i = 0; i < strlen ( str ) ; i ++) {
if ( str [ i ] == match [ c ] && c < strlen ( match ) ) {
11 c ++;
} else {
13 c = 0;
}
15 if ( c == strlen ( match ) ) {
printf ( " Pattern matched after % d chars \ n " ,
17 i - strlen ( match ) + 1) ;
}
19 }
return 0;
21 }
✆✌

Pattern matched after 2 chars
Pattern matched after 5 chars
Pattern matched after 14 chars
✆✌

strstr
The syntax of strstr () function is
160 Basic C


1 char * strstr ( const char * string , const char * sub - str ) ;
✆✌
The strstr () function shall locate the first occurrence in the string pointed-by ‘string’
of the sequence of bytes (excluding the terminating null byte) in the string pointed-by
‘sub-str’. It returns the pointer (or may say the address) of the first occurrence of the
sub-string. A simple example is

1 # include < stdio .h >
# include < string .h >
3

int main () {
5 /* initialize an experimental string */
char str [ ] = " This is a simple string " ;
7 char * pch ;
/* get first occurance of simple */
9 pch = strstr ( str , " simple " ) ;
puts ( pch ) ;
11 return 0;
}
✆✌

simple string
✆✌

pch = strstr(str, ”simple”);

T h i s i s a s i m p l e s t r i n g \0

pch s i m p l e s t r i n g \0

strtok
The syntax of strtok function is

1 char * strtok ( char * restrict s1 , const char * restrict delimiters );
✆✌
A sequence of calls to strtok () breaks the string pointed-by ‘s1’ into a sequence of tokens,
each of which is delimited by a byte from the string pointed-by delimiters. This function
returns the address of memory location where tokenised string is stored. first cA simple
example is

1 # include < stdio .h >
# include < string .h >
3

int main () {
5 /* experimental string */
char str [ ] = " - This is my country . " ;
1.8. STRINGS 161

7 /* pointer for string tokenization */


char * pch ; /* Do not need memory allocation , as it *
9 * has to point the memory address *
* being returned by strtok function . */
11 printf ( " String \"% s \" is splitted into tokens :\ n " , str ) ;
/* break experimental string with *
13 * spacecomma dot and doublequote */
pch = strtok ( str , " ,. - " ) ;
15 while ( pch != NULL ) {
printf ( " % s \ n " , pch ) ;
17 pch = strtok ( NULL , " ,. - " ) ;
}
19 return 0;
}
✆✌

String " - This is my country ." is splitted into into tokens :
This
is
my
country
✆✌
Here is an example which splits the string by a delimiter without using strtok () function.
In this example, a string is read character by character and when a read character is equal
to the delimiter, a new line is started.

1 # include < stdio .h >

3 int main ( int argc , char * argv [ ]) {


if ( argv [1] == NULL ) {
5 printf ( " Use < utility . exe > < string in double quote >
< delimiter >.\ n " ) ;
exit (0) ;
7 }
/* get the commandline string */
9 char * Str = argv [1];
char * Del = argv [2];
11 printf ( " The delimiter is ’% s ’.\ n " , Del ) ;
printf ( " The broken strings are : \ n \ n " , Del ) ;
13 int i = 0;
while ( Str [ i ] != NULL ) {
15 if ( Str [ i ] == Del [0]) {
printf ( " \ n " ) ;
17 i ++;
}
19 printf ( " % c " , Str [ i ]) ;
i ++;
21 }
printf ( " \ n \ nThe length of string supplied is % d .\ n " , i ) ;
23 return 0;
}
✆✌
162 Basic C


executable . exe " This is my name " " "
This
is
my
name

The length of string supplied is 15.


✆✌

strtod
The strtod (), strtof (), and strtold () functions convert the initial portion of the string
pointed-by pointer to double, float, and long double representation, respectively. The
return value is numerical value and pointer stores the rest of string.

1 # include < stdio .h >
# include < stdlib .h >
3

int main () {
5 char str [30] = " 20.30300 Rs are spent . " ;
char * ptr ;
7 double ret ;

9 ret = strtod ( str , & ptr ) ;


printf ( " The Rs in ( double ) is % lf \ n " , ret ) ;
11 printf ( " |% s |\ n " , ptr ) ;

13 return (0) ;
}
✆✌

The Rs in ( double ) is 20.303000
| Rs are spent .|
✆✌

1.9 Function
Function in C a group of statements and expressions which accepts inputs, analyse them
according to the statements and expressions, and return the result.

int sum ( int a , int b ) {
2 < function body expressions >
}
✆✌
A function is like a black box. It takes inputs and do something and throws an output.
A function may be declared with or without definition as shown below:

1 int myFunc () ; // Function declared without definition
int myFunc () {} // Function declared with definition
✆✌
1.9. FUNCTION 163

1.9.1 Function Arguments


A functions accepts inputs through its arguments. A function with two arguments (or
parameters) is defined as

int sum ( int a , int b ) ;
✆✌
These parameters in a function definition are called formal arguments. Here, int a, int b
are known as formal arguments. During the defining of a function, each argument must
be identified by its type. For example, to supply two integer arguments to a function, it
shall be defined like

1 int sum ( int a , int b ) ;
✆✌
while, the definition of function as given below is illegal.

1 int sum ( int a , b ) ; // Illegal definition
✆✌
Here, second argument ‘b’ is type unidentified. A function can be called from anywhere
by supplying actual arguments. The supplied argument to a function are type casted
according to the type of the function argument. For example, when a function type

1 int sum ( int a , int b ) ;
✆✌
is called as

1 sum (2.5 , 2) ;
✆✌
then the function accepts argument value (or actual arguments) 2.5 as a = 2 because, ar-
gument a is an integer type and supplied argument is float type. While, b = 2. Therefore,
decimal part of the float value is truncated. See example below.

1 # include < stdio .h >

3 /* Sum function with formal arguments */


int sum ( int a , int b ) {
5 int f ;
f = a + b;
7 return f ;
}
9

int main ( int argc , char * argv [ ]) {


11 int g ;
/* Sum function with actual arguments */
13 g = sum (2.5 , 2) ;
printf ( " Sum of % f and % d is % d \ n " , 2.5 , 2 , g ) ;
15 return 0;
}
✆✌

Sum of 2.5 and 2 is 4
✆✌
164 Basic C

Two dimensional arrays of integer type may also be passed as function argument. Two
dimensional, integer type and static size array is passed to function as shown below:

1 # include < stdio .h >

3 void myFunc ( int myArray [3][3]) {


int i , j ;
5 for ( i = 0; i < 3; i ++) {
for ( j = 0; j < 3; j ++) {
7 printf ( " % d \ t " , myArray [ i ][ j ]) ;
}
9 printf ( " \ n " ) ;
}
11 }

13 int main () {
int myArray [][3] = {
15 {1 , 2 , 3} ,
{4 , 5 , 6} ,
17 {7 , 8 , 9}
};
19 myFunc ( myArray ) ;
return 0;
21 }
✆✌

1 2 3
4 5 6
7 8 9
✆✌
If height of the two dimensional array is dynamic and only width is fixed then two
dimensional integer type array is passed to a function. The unknown dimension of the
array should be passed to the function as its another parameter.

1 # include < stdio .h >

3 void myFunc ( int myArray [][3] , int m ) {


int i , j ;
5 for ( i = 0; i < m ; i ++) {
for ( j = 0; j < 3; j ++) {
7 printf ( " % d \ t " , myArray [ i ][ j ]) ;
}
9 printf ( " \ n " ) ;
}
11 }

13 int main () {
int myArray [3][3] = {
15 {1 , 2 , 3} ,
{4 , 5 , 6} ,
17 {7 , 8 , 9}
};
1.9. FUNCTION 165

19 myFunc ( myArray , 3) ;
return 0;
21 }
✆✌

1 2 3
4 5 6
7 8 9
✆✌
A dynamic two dimensional integer type array may passed to a function as its argument
in pointer form. Remember that as two dimensional array passed to function a pointer
only and the called function does not know the actual size of the passed array. Therefore,
dimensions of the array must be passed as another parameters of the function.

1 # include < stdio .h >

3 /* Catch myArray pointer as parameter of *


* function . myr parameter points to passed *
5 * array as 1 D array not as 2 D array . */
void myF ( int * mAr , int m , int n ) {
7 int i , j ;
for ( i = 0; i < m ; i ++) {
9 for ( j = 0; j < n ; j ++) {
/* Print the array elements row by row . */
11 printf ( " % d " , *(( mAr + i * n ) + j ) ) ;
}
13 printf ( " \ n " ) ;
}
15 }

17 int main () {
int myArray [][3] = {
19 {4 , 5 , 6} ,
{1 , 2 , 3} ,
21 {9 , 8 , 7}
};
23 /* Pass myArray as a pointer . */
myF (( int *) myArray , 3 , 3) ;
25 return 0;
}
✆✌

4 5 6
1 2 3
9 8 7
✆✌
166 Basic C

Pass A
rray to Fun
ction

myArray[m][n]= 11 12 13 14 15
21 22 23 24 25
i
31 32 33 34 35 myF((int *) myArray, ...)
41 42 43 44 45
51 52 53 54 55
j

In above example, array is passed as pointer and the address of the array pointer is catches
by the function as its parameter. Notice that, inside the function, array pointer does not
represents to two dimensional array but represents to one dimensional array as a group
of bytes in row by row order. This is why, in this function the dimensions of the array are
passed via two additional parameters. These parameters are used to control the printing
of each element of the passed array.

Array as Argument

void myF(int *mAr, ...){...} 11 12 13 14 15 21 22 23 24 25 ...

*((mAr+i*n)+j) *((mAr+i*n)+j)

Now, again, in C, a function without any argument can be compiled ans run by calling
with any number of arguments. See the example below:

1 # include < stdio .h >

3 void testFun () { } // Function declared without arguments

5 int main ( void ) {


// Function called with three argument .
7 testFun (10 , " x " , " Y " ) ;
return 0;
9 }
✆✌
But if the argument of prototype function is void type then the program fails to compile
and run. See below:

1 # include < stdio .h >

3 void testFun ( void ) { } // Function declared with void arguments

5 int main ( void ) {


// Function called with three argument .
7 testFun (10 , " x " , " Y " ) ;
return 0;
9 }
✆✌
1.9. FUNCTION 167

1.9.2 Function Prototype


The declaration of a function prototype tell the compiler three important things about
it:
1. to expect to encounter them further down the program;
2. the return types of the function, e.g. void, int or double;
3. the number and kind of arguments the function is to handle;
The parameter names listed in a function’s prototype may be same as in the function’s
declaration or not. Function prototype allows to omit the variable name in its arguments.
The legal function prototyping are

1 int sum ( int , int ) ; /* Legal prototype . */
int sum ( int a , int b ) ; /* Legal prototype . */
3 int sum (a , int b ) ; /* Illegal prototype . */
int sum ( int * , int * a ) ; /* Legal prototype with pointer array . */
5 int sum ( int * , int & a ) ; /* Illegal prototype with address of a */
int sum ( int [ ] , int a [ ]) ; /* Legal prototype with array . */
✆✌
Function prototyping is required when a function is called from the body of another
function which is defined above the called function. It also needed to be declared if
function is envoked before its definition as shown in the below example.

# include < stdio .h >
2 /* Prototype is required . */
void swap ( int * u , int * v ) ;
4

int main ( void ) {


6 int x = 5 , y = 10;
printf ( " Originally x = % d and y = % d .\ n " , x , y ) ;
8 swap (& x , & y ) ; /* Send addresses to function */
printf ( " Now x = % d and y = % d .\ n " , x , y ) ;
10 return 0;
}
12

void swap ( int * u , int * v ) {


14 int temp ;
temp = * u ; /* temp gets value that u points to */
16 * u = * v ; /* Store the value of v at address of x */
* v = temp ; /* Store the value of u at address of y */
18 }
✆✌

Originally x = 5 and y = 10.
Now x = 10 and y = 5.
✆✌
If prototype is not declared, then the compiler shows errors as in the following example,
function is envoked before the definition of the function.
168 Basic C


# include < stdio .h >
2 /* Prototype is disabled . */
// void swap ( int * u , int * v ) ;
4

int main ( void ) {


6 int x = 5 , y = 10;
printf ( " Originally x = % d and y = % d .\ n " , x , y ) ;
8 swap (& x , & y ) ; /* send addresses to function */
printf ( " Now x = % d and y = % d .\ n " , x , y ) ;
10 return 0;
}
12

void swap ( int * u , int * v) {


14 int temp ;
temp = * u ; /* temp gets value that u points to */
16 *u = *v; /* Store the value of v at address of x */
* v = temp ; /* Store the value of u at address of y */
18 }
✆✌
Again, if a function is called from the body of another function which is defined below to
the called function, then declaration of prototype is not required.

# include < stdio .h >
2

void swap ( int * u , int * v) {


4 int temp ;
temp = * u ; /* temp gets value that u points to */
6 *u = *v; /* Store the value of v at address of x */
* v = temp ; /* Store the value of u at address of y */
8 }

10 int main ( void ) {


int x = 5 , y = 10;
12 printf ( " Originally x = % d and y = % d .\ n " , x , y ) ;
swap (& x , & y ) ; /* send addresses to function */
14 printf ( " Now x = % d and y = % d .\ n " , x , y ) ;
return 0;
16 }
✆✌

Originally x = 5 and y = 10.
Now x = 10 and y = 5.
✆✌
Another point is to be remembered that C compiler assumes a function as integer return
type by default. If user defined function is declared as integer type, then C compiler does
not failed to compile a function without prototype declaration. If user defined function
returns other values then compiler fails to compile the program. The following example
compiled successfully.

# include < stdio .h >
2 /* Declaring prototype */
1.9. FUNCTION 169

char myFunc () ;
4

int main ( void ) {


6 /* Calling function of integer type return . */
printf ( " Calling function myFunc () \ n " ) ;
8 printf ( " Returned value is % c " , myFunc () ) ;
return 0;
10 }

12 /* Declaring function of char type return . */


char myFunc () {
14 return ’A ’;
}
✆✌

Calling function myFunc ()
Returned value is A
✆✌
Above function is re-written without declaring prototype. This program is failed to
compile.

# include < stdio .h >
2

int main ( void ) {


4 /* Calling function of integer type return . */
printf ( " Calling function myFunc () \ n " ) ;
6 printf ( " Returned value is % c " , myFunc () ) ;
return 0;
8 }

10 /* Declaring function of char type return . */


char myFunc () {
12 return ’A ’;
}
✆✌
There is no problem if the function is declared with integer return type. See the example
below which is modified form of above function.

1 # include < stdio .h >

3 int main ( void ) {


/* Calling function of integer type return . */
5 printf ( " Calling function myFunc () \ n " ) ;
printf ( " Returned value is % c " , myFunc () ) ;
7 return 0;
}
9

/* Declaring function of integer type return . */


11 int myFunc () {
return ’A ’;
13 }
✆✌
170 Basic C


Calling function myFunc ()
Returned value is A
✆✌
Compiler does not care about parameters of the declared function prototype. The com-
piler will not be able to perform compile-time checking of argument types. The validity
of arguments is checked during the program run time and sometime program returns
garbage value.

# include < stdio .h >
2

int main ( void ) {


4 /* Calling function of integer type return . */
printf ( " Calling function myFunc () \ n " ) ;
6 printf ( " Returned value is % c " , myFunc (65) ) ;
return 0;
8 }

10 /* Declaring function of integer type return . */


int myFunc ( int i , int j ) {
12 return i + j ;
}
✆✌

1.9.3 Function Types


In old C standards, each function was considered as integer type, while in new implemen-
tation of C standards, the type of the function may be integer, float, double, character
or void. Declaration of a function type is based on the return value of the function not
on the argument type. See example below:

1 # include < stdio .h >
/* Integer type function . */
3 int max ( int a , int b ) {
if ( a > b )
5 return a ;
else
7 return b ;
}
9

int main ( int argc , char * argv [ ]) {


11 /* integer specifier required to *
* print return value from function . */
13 printf ( " Max of % d and % d is % d \ n " , 2 , 3 , max (2 , 3) ) ;
return 0;
15 }
✆✌

Max of 2 and 3 is 3
✆✌
1.9. FUNCTION 171

In function ‘max’, two arguments are taken as inputs as integer and between them, greater
is returned as integer. Hence, here the function is declare as integer type. If the same
function is declared as float type then return value is a float value not integer value.

1 # include < stdio .h >
/* Float type function . */
3 float max ( int a , int b ) {
if ( a > b )
5 return a ;
else
7 return b ;
}
9

int main ( int argc , char * argv [ ]) {


11 /* Float specifier required to print *
* return value from function . */
13 printf ( " Max of % d and % d is % f \ n " , 2 , 3 , max (2 , 3) ) ;
return 0;
15 }
✆✌

Max of 2 and 3 is 3.0000
✆✌
In case of void functions, the function should return with NULL value even if return
keyword is used inside the function. This type of function do something according to its
expression and stores the result in global variable.

1 # include < stdio .h >
int f ;
3

void sum ( int a , int b ) {


5 f = a+b;
/* Use of return keyword without any value . */
7 return ;
}
9

int main ( int argc , char * argv [ ]) {


11 sum (2 , 3) ;
printf ( " Sum of % d and % d is % d \ n " , 2 , 3 , f ) ;
13 return 0;
}
✆✌

Sum of 2 and 3 is 5
✆✌
Use of return keyword in following manner are valid in void type functions.

1 return ; /* Legal return */
return " " ; /* Legal return */
3 return NULL ; /* Legal return */
return " ; /* Illegal , " is null character code */
✆✌
172 Basic C

return keyword is somewhat like exit keyword. After return keyword, anything inside
an expression block is skipped during program execution. Function returns the assigned
value and exits.

# include < stdio .h >
2

int ret () ;
4

int main ( void ) {


6 ret () ;
return 0;
8 }

10 int ret () {
int i = 0;
12 int loops = 15;
printf ( " Loop count is % d \ n " , loops ) ;
14 while ( i < loops ) {
printf ( " i is % d \ n " , i ) ;
16 if ( i == 7) {
printf ( " Returning from the function at i =% d \ n " , i ) ;
18 printf ( " reaching before the loop value % d \ n " , loops );
return 0;
20 }
i ++;
22 }
return 0;
24 }
✆✌

Loop count is 15
i is 0
i is 1
i is 2
i is 3
i is 4
i is 5
i is 6
i is 7
Returning from the function at i =7
reaching before the loop value 15
✆✌
A function with void return type can not be called through printf. For example

1 # include < stdio .h >
# include < stdlib .h >
3

/* function return type is void */


5 void myF () {
printf ( " myF " ) ;
7 }
1.9. FUNCTION 173

9 int main () {
int i = 5 , j = 3;
11 /* invalid use of void type function */
printf ( " % s " , myF () ) ;
13

return 0;
15 }
✆✌
program failed to compile and returns compile time error “invalid use of void ”.
Never Reach Condition A function with return keyword, returns either NULL or some
alpha-numeric value after successful execution. Execution of function-script is terminated
after first successful return. If a function is designed in such manner that it has to reached
to only fixed return keywords then other return keywords if used are never reached by
the compiler. See the example given below:

1 # include < stdio .h >

3 int executeMe ( int i ) {


if ( i <= 10) { /* If i is less than or equal to 10 */
5 return 0;
} else { /* Otherwise */
7 return 1;
}
9 return -1; /* Mever reached */
}
11

int main () {
13 printf ( " % d \ n " , executeMe (10) ) ;
printf ( " % d \ n " , executeMe (15) ) ;
15 printf ( " % d \ n " , executeMe (1) ) ;
return 0;
17 }
✆✌

0
1
0
✆✌

1.9.4 Function Recursion


In C, a function can be called recursively, i.e. in nested form from within its body, without
using loop functions, i.e. for, while or do-while etc. See the example given below:

1 # include < stdio .h >
int recFunc ( int i , int j ) ;
3

int recFunc ( int i , int j ) {


5 if ( i == 0) {
return (2 + j ) ;
174 Basic C

7 } else {
return recFunc ( i - 1 , j + 1) ;
9 }
}
11

int main ( int argc , char ** argv ) {


13 int k = recFunc (4 , 6) ;
printf ( " % d " , k ) ;
15 return 0;
}
✆✌

12
✆✌
In above example, function ‘recFunc’ takes two arguments and checks the conditions for
its first argument. If it is true then it returns the sum of ‘2’ and second argument and
exits. Otherwise it returns the function ‘recFunc’ with new values of its two arguments.
As function calls itself, hence a loop like recursion is observed. There should be a condition
to be met and break the function recursion otherwise there shall be no return value. See
the following examples,

1 # include < stdio .h >
int recFunc ( int i , int j ) ;
3

/* This type of recursion is not acceptable . */


5 int recFunc ( int i , int j ) {
/* No Condition , No return value . */
7 return recFunc ( i - 1 , j + 1) ;
}
9

int main ( int argc , char ** argv ) {


11 int k = recFunc (4 , 6) ;
printf ( " % d " , k ) ;
13 return 0;
}
✆✌
If condition in the recursive function is not met then there is no return value from the
function. In the following example, if condition is never met therefore, there shall be no
return value from the recursive function.

# include < stdio .h >
2 int recFunc ( int i , int j ) ;

4 int recFunc ( int i , int j ) {


/* Condition never met . No returned value . */
6 if ( i == 0) {
return (2 + j ) ;
8 } else {
return recFunc ( i , j + 1) ;
10 }
}
1.9. FUNCTION 175

12

int main ( int argc , char ** argv ) {


14 int k = recFunc (1 , 6) ;
printf ( " % d " , k ) ;
16 return 0;
}
✆✌
There shall be no output on running of above two program.

1.9.5 Function As Argument


A function can pass to another function as its argument. The synopsis of the passing of
a function as argument to the other function tFunc() is given below:

1 void tFunc ( < data type > (* < func pointer >) () ) ;
✆✌
See the example :

1 # include < stdio .h >
# include < math .h >
3

/* Here * fp is pointer of the function sqrt */


5 void tFunc ( char * name , double (* fp ) () ) {
int n ;
7 printf ( " Testing function % s :\ n " , name ) ;
printf ( " % s : %10 s \ n " , " n " , " Square Root " ) ;
9 printf ( " - - - - - - - - - - - - - -\ n " ) ;
for ( n = 0; n < 10; n ++) {
11 printf ( " % d : %11.6 f \ n " , n , (* fp ) (( double ) n ) ) ;
}
13 }

15 int main () {
tFunc ( " square root " , sqrt ) ;
17 return 0;
}
✆✌

Testing function square root :
n : Square Root
--------------
0: 0.000000
1: 1.000000
2: 1.414214
3: 1.732051
4: 2.000000
5: 2.236068
6: 2.449490
7: 2.645751
8: 2.828427
9: 3.000000
✆✌
176 Basic C

1.9.6 Function Callback


A callback is a piece of executable code that is passed as an argument to other code,
which is expected to call back (execute) the argument at some convenient time. In C,
there is no “callback” yet they are implemented by using function pointers. Following
example shows the possible call back.

1 # include < stdio .h >

3 /* This function is calledback from other function . */


int DoubleIt ( int a ) {
5 return 2 * a ;
}
7

/* Pass DoubleIt function as argument named fPar .*


9 * The argument should be as function prototype . */
int myFunc ( int (* fPar ) ( int ) ) {
11 int i = 10;
fPar ( i ) ;
13 }

15 int main () {
/* Pass function DoubleIt to myFunc */
17 printf ( " Result is : % d \ n " , myFunc ( DoubleIt ) ) ;
return 0;
19 }
✆✌

Result is : 20
✆✌
The same above example is given in pointer format.

1 # include < stdio .h >

3 /* This function is calledback from other function . */


int * DoubleIt ( int a ) {
5 int * i ;
i = (2 * a ) ;
7 }

9 /* Pass DoubleIt function as argument named fPar .*


* The argument should be as function prototype . */
11 int * myFunc ( int (* fPar ) ( int ) ) {
int i = 10;
13 (* fPar ) ( i ) ;
}
15

int main () {
17 /* Pass function DoubleIt to myFunc */
printf ( " Result is : % d \ n " , myFunc ( DoubleIt ) ) ;
19 return 0;
}
✆✌
1.9. FUNCTION 177


Result is : 20
✆✌
A function may be called from its pointer index if function pointer is saved in function
symbol table. See the example given below:

1 # include < stdio .h >
# include < stdlib .h >
3 # include < dlfcn .h >

5 /* Memory allocation for 5 Function Pointers */


int (* FP [5]) () ;
7

main ( int argc , char ** argv ) {


9 int i = 0;
void * myLib ;
11

/* Function pointer */
13 void * fptr ;

15 /* Load function library */


myLib = dlopen ( " libtestdll . dll " , RTLD_LAZY ) ;
17

/* Find the function object of function " bar " */


19 fptr = dlsym ( myLib , " bar " ) ;

21 /* Assign address of library function " bar "*


* to all indexed function pointers ( FP ) */
23 for ( i = 0; i < 5; i ++) {
FP [ i ] = fptr ;
25 }

27 /* Call function from second FP address */


FP [1]() ;
29

/* Close Library */
31 dlclose ( myLib ) ;

33 return 0;
}
✆✌

called bar function from dll .
✆✌

1.9.7 Memory Function


Memory functions in C, deals with memory. These functions are used to store, copy and
move data from one memory location to other memory location.
178 Basic C

mmap
To read or write to same file by two or more processes, mmap() function is used. Before
mapping a file to memory, file descriptor is obtained by using open() function as given
below:

1 int fd ;
fd = open ( " < file name > " , " < mode > " ) ;
✆✌
The open function returns the file descriptor as integer value. ‘-1’ if it failed to open the
file otherwise a positive integer as file handle. Now, mmap() is called to map the file as

data = mmap ( < address > , < size > , < prot > , < flags > , < file id > ,
< offset >) ;
✆✌
‘address’ is the memory address where we want to mapped a file. By default its value is
‘0’ for automatic selection of address by the OS. ‘size’ is length of data of the file to be
mapped. ‘prot’ is a kind of access/permission to the file. Its values are PROT READ
for read only permission, PROT WRITE for write only permission and PROT EXEC for
execute permissions. ‘flags’ controls the sharing of changes or just keep them private.
The flag values are MAP SHARED or MAP PRIVATE for sharing and private mode
respectively. ‘offset’ is initial position of the file from where mapping of file data to
memory started. This value must be a multiple of the virtual memory page size. To get
the page size, getpagesize() function is used. See the example below:

1 # include < stdio .h >
# include < stdlib .h >
3 # include < sys / mman .h >
# include < fcntl .h >
5

int main ( int argc , char * argv []) {


7 int fd ;
char * data ;
9 /* Read only mode of file . */
if (( fd = open ( " a . txt " , O_RDONLY ) ) == -1) {
11 printf ( " Unable to open file " ) ;
return 1;
13 }
/* Map file in memory with read only permissions */
15 data = mmap (0 , 1024 , PROT_READ , MAP_SHARED , fd , 0) ;
if (* data == -1) {
17 printf ( " Unable to map file " ) ;
return 1;
19 }
printf ( " Byte at offset % d is ’% c ’\ n " , 0 , data [0]) ;
21 return 0;
}
✆✌

Byte at offset 0 is ’s ’
✆✌
1.9. FUNCTION 179

Each file which is mapped must be freed by using munmap function as



1 int munmap ( < address > , < size >) ;
✆✌
Once the file is unmapped, data access with old file descriptor is not possible and will
return segmentation fault error. If multiple protected access permissions are granted by
using OR (|) operator in mmap() function, then the file access mode should be according
the access granted. See the example below in which protected access mode is grated for
read and write. Therefore, the file access mode in open() function is “rw” type (i.e. read
and write type via O RDWR).

1 # include < stdio .h >
# include < stdlib .h >
3 # include < sys / mman .h >
# include < fcntl .h >
5

int main ( int argc , char * argv []) {


7 int fd ;
char * data ;
9 /* Read and write mode of file . */
if (( fd = open ( " a . txt " , O_RDWR ) ) == -1) {
11 printf ( " Unable to open file " ) ;
return 1;
13 }
/* Map file in memory with read & write permissions */
15 data = mmap (0 , 1024 , PROT_READ | PROT_WRITE , MAP_SHARED , fd , 0) ;
if (* data == -1) {
17 printf ( " Unable to map file " ) ;
return 1;
19 }
printf ( " Byte at offset % d is ’% c ’\ n " , 0 , data [0]) ;
21 data [10] = ’1 ’;
printf ( " Byte at offset % d is ’% c ’\ n " , 10 , data [10]) ;
23 return 0;
}
✆✌

Byte at offset 0 is ’a ’
Byte at offset 10 is ’1 ’
✆✌

File Mode Key Numeric Description


O RDONLY 0 Read only access to file.
O WRONLY 1 Write only access to file.
O RDWR 2 Read and write access to file.

Table 1.21: File access mode.


180 Basic C

A segment of file may be mapped by using mmap function with setting file pointer by
lseek function as given below:

....
2 for ( j = 0; j <= bk ; j ++) {
/* Map file for block size ‘ bks ’ from ‘ offset ’ */
4 data = mmap (0 , bks , PROT_READ | PROT_WRITE , \
MAP_SHARED , fd , offset ) ;
6 /* Chagne file pionter ‘ fd ’ to next block */
int offset = lseek ( fd , bks , SEEK_CUR ) ;
8 }
....
✆✌

File Access Modes


The protection and permission codes of a file in Linux OS system are given in the following
table.

Mode Permission Value Protection Value


NONE 0 0
READ 4 1
WRITE 2 2
EXEC 1 4

Permission to a file in Linux OS system for a user, group or system is managed by


chmod command. This command accepts the file protection mode in numeric form as
given below:

1 chmod 777 < file or dir >
✆✌
In Linux OS system, a file has three levels of discretionary protection and permission.
permission to a file in Linux OS system is represented by a string that looks like “Zrwxr-
wxrwx”, in which first character, ‘Z’ defined type of directory or file, i.e. ‘d’ for directory,
‘l’ for linked file, ‘s’ for setuid bit, ‘t’ for the sticky bit etc. Next three characters (triads)
are protection/permission mode for owner, second is for group and third is for all other
users. Character ‘r’, ‘w’ and ‘x’ represents to read, write and execute modes respectively.
If user has readonly permission to a file then three characters shall be looked like ‘r –
–’ where dashes represent no write and no execute permissions to the user for the given
file or directory. The permission code in chmod command, as given above is splited in
all possible combinations before defining user’s permission and execution of chmod com-
mand. Note that, in permission code ‘777’, first ‘7’ is for owner second ‘7’ is for group
and third ‘7’ is for all other users. For example, ‘7’ is splitted in 4+2+1 form to mark
a file as read-write-exec. ‘3’ as 0+2+1, i.e. read-write- –. ‘5’ as 4+0+1, i.e. read- – -
exec. Permission with ‘–’ means files can not be either read, write or permissioned and
directories can not be permissioned with cd command. If there is no valid combinations
1.9. FUNCTION 181

are made from permission code, then invalid mode error is thrown by the system. The
permission string can be equivalently computed with binary values as shown below:

1 - rwxrwxrwx ; permission string
111111111 ; Binary values
✆✌
The triad values for owner (let) are computed for read permission as 1002 = 410 , for write
permission as 0102 = 210 , for read-write 1102 = 610 and so on.

memset
Syntax of memset () function is

void * memset ( void *s , int c , size_t n ) ;
✆✌
The memset () function converts ‘c’ into unsigned char, then stores the character into the
first ‘n’ bytes of memory pointed-by ‘s’. A simple example is

1 # include < stdio .h >
# include < string .h >
3

int main () {
5 /* iniitalized a string */
char str1 [ ] = " These is memset !!!! " ;
7 /* memset first six characters of the string */
memset ( str1 , ’ - ’ , 6) ;
9 puts ( str1 ) ;
/* iniitalized a string */
11 char str2 [ ] = " These is memset !!!! " ;
/* memset first three characters of the string */
13 memset ( str2 , ’ - ’ , 3) ;
puts ( str2 ) ;
15 /* iniitalized a string */
char str3 [ ] = " These is memset !!!! " ;
17 /* memset first four characters of the string */
memset ( str3 , ’ - ’ , 4) ;
19 puts ( str3 ) ;
return 0;
21 }
✆✌

------ is memset !!!!
--- se is memset !!!!
---- e is memset !!!!
✆✌

memcpy
The memcpy() function shall copy n bytes from the object pointed to by ‘source’ into the
object pointed to by ‘destination’. If copying takes place between objects that overlap,
the behavior is undefined. The function returns ‘destination’. Syntax of the function is
182 Basic C


1 void * memcpy ( void * restrict < destination > , \
const void * restrict < source > , size_t <n >) ;
✆✌
Because the function does not have to worry about overlap, it can do the simplest copy
it can.

# include < stdio .h >
2 # include < string .h >

4 int main () {
const char src [50] = " Experimental string . " ;
6 char dest [50];

8 printf ( " Before memcpy destination is : % s \ n " , dest ) ;


memcpy ( dest , src , strlen ( src ) + 1) ;
10 printf ( " After memcpy destination is : % s \ n " , dest ) ;

12 return (0) ;
}
✆✌

Before memcpy destination is :
After memcpy destination is : Experimental string .
✆✌
memcpy() function is very useful when a user defined function pointer is required to
return the local pointer defined inside the function.

# include < stdio .h >
2

char * toLower ( char str [ ]) {


4 /* Initiate local string pointer */
char * s = NULL ;
6 /* Allocate memory for local pointer */
s = malloc ( sizeof ( char ) *(1024) ) ;
8 int i = 0;
/* Create a local array for storing *
10 * modified string received from *
* from function argument . */
12 char st [1024];
while ( str [ i ] != ’ \0 ’) {
14 /* Capital letters starts from *
* char code 65 to 90. While *
16 * small letters starts from 97*
* to 122. A difference of +32 */
18 if ( str [ i ] >= 65 && str [ i ] <= 90) {
st [ i ] = str [ i ] + 32;
20 } else {
st [ i ] = str [ i ];
22 }
i ++;
24 }
1.9. FUNCTION 183

st [ i ] = ’ \0 ’;
26 /* Copy array into memory as a pointer . */
memcpy (s , st , 1024) ;
28 /* Return function pointer . */
return s ;
30 /* Free allocated memory . */
free ( s ) ;
32 }

34 int main ( void ) {


char str [ ] = " This iS MY striNg . " ;
36 printf ( " Actual string is : " ) ;
printf ( " \"% s \"\ n " , str ) ;
38 printf ( " Lower case string is : " ) ;
printf ( " \"% s \" " , toLower ( str ) ) ;
40 return 0;
}
✆✌

Actual string is : " This iS MY striNg ."
Lower case string is : " this is my string ."
✆✌

memmov
The memmove() function shall copy n bytes from the object pointed to by ‘source’ into
the object pointed to by ‘dest’. Copying takes place as if the n bytes from the object
pointed to by ‘source’ are first copied into a temporary array of n bytes that does not
overlap the objects pointed to by ‘dest’ and ‘source’, and then the n bytes from the
temporary array are copied into the object pointed to by ‘dest’. The function returns the
value of ‘dest’. The easy way to implement this without using a temporary array is to
check for a condition that would prevent an ascending copy, and if found, do a descending
copy. Unlike the memcpy(), this function guaranteed to move contents from source to
destination even if the memory regions pointed by ‘source’ and ‘dest’ overlaps. Its syntax
is

void * memmove ( void * <dest > , const void * < source > , size_t <n >) ;
✆✌

1 # include < stdio .h >
# include < string .h >
3

int main () {
5 char str [ ] = " Experimental string " ;
memmove ( str + 10 , str + 5 , 5) ;
7 puts ( str ) ;
return 0;
9 }
✆✌

Experiment i m en t ri n g
✆✌
184 Basic C

memchr
The memchr() function shall locate the first occurrence of ‘c’ (converted to an unsigned
char) in the initial n bytes (each interpreted as unsigned char) of the object pointed to
by ‘string’. If ‘c’ is not found, memchr() returns a null pointer. Its syntax is

1 void * memchr ( const void * < string > , int <c > , size_t <n >) ;
✆✌

1 # include < stdio .h >
# include < string .h >
3

int main () {
5 char * pch ;
char str [ ] = " Example string " ;
7 pch = ( char *) memchr ( str , ’e ’ , strlen ( str ) ) ;
if ( pch != NULL )
9 printf ( " ’e ’ found at position % d .\ n " , pch - str + 1) ;
else
11 printf ( " ’e ’ not found .\ n " ) ;
return 0;
13 }
✆✌

’e ’ found at position 7.
✆✌

memcmp
The memcmp() function shall compare the first n bytes (each interpreted as unsigned
char) of the object pointed to by ‘mem1’ to the first n bytes of the object pointed to
by ‘mem2’. The sign of a non-zero return value shall be determined by the sign of the
difference between the values of the first pair of bytes (both interpreted as type unsigned
char) that differ in the objects being compared.

1 int memcmp ( const void * < mem1 > , const void * < mem2 > , size_t <n >) ;
✆✌

1 # include < stdio .h >
# include < string .h >
3

int main () {
5 char buff [ ] = " Artificial " ;
char buff2 [ ] = " ARtificial " ;
7

int n ;
9

n = memcmp ( buff , buff2 , sizeof ( buff ) ) ;


11

if ( n > 0)
13 printf ( " ’% s ’ is greater than ’% s ’.\ n " , buff , buff2 ) ;
else if ( n < 0)
15 printf ( " ’% s ’ is less than ’% s ’.\ n " , buff , buff2 ) ;
1.9. FUNCTION 185

else
17 printf ( " ’% s ’ is the same as ’% s ’.\ n " , buff , buff2 ) ;

19 return 0;
}
✆✌

’ Artificial ’ is greater than ’ ARtificial ’.
✆✌

1.9.8 Unicode Support


C provides unicode support for the native operating systems which have their own unicode
support. To set the native local language

1 char * locale = setlocale ( LC_CTYPE , " en_IN . UTF -8 " ) ;
✆✌
The function setlocale() is defined in the macro “locale.h”. If native locale doesn’t use
UTF-8 encoding it need to replace the empty string with a locale like “en IN.UTF-8”.
Localisation environment has following parameters

1 ANG = en_US
LC_CTYPE = " en_US "
3 LC_NUMERIC = " en_US "
LC_TIME = " en_US "
5 LC_COLLATE = " en_US "
LC_MONETARY = " en_US "
7 LC_MESSAGES = " en_US "
LC_PAPER = " en_US "
9 LC_NAME = " en_US "
LC_ADDRESS = " en_US "
11 LC_TELEPHONE = " en_US "
LC_MEASUREME NT = " en_US "
13 LC_IDENTIF IC A TI ON = " en_US "
LC_ALL =
✆✌
User can change any specific environmental parameter by using method given above or
setting all environment to locals by setting ‘LC ALL’ as shown below.

char * locale = setlocale ( LC_ALL , " en_IN . UTF -8 " ) ;
✆✌
An example is

1 # include < stdio .h >
# include < wchar .h >
3 # include < stdlib .h >
# include < locale .h >
5

int main ( void ) {


7 /* If your native locale doesn ’t use UTF -8 encoding *
* you need to replace the empty string with a *
186 Basic C

9 * locale like " en_US . utf8 " */


char * locale = setlocale ( LC_CTYPE , " en_IN . UTF -8 " ) ;
11 FILE * in = fopen ( " a . txt " , " r " ) ;

13 wint_t c ;
while (( c = fgetwc ( in ) ) != WEOF )
15 putwchar ( c ) ;
fclose ( in ) ;
17

return EXIT_SUCCESS ;
19 }
✆✌

1.10 Procedures & Functions


A function is often executed (called) several times, called from different locations, during
a single execution of the program. After finishing a subroutine, the program will branch
back (return) to the point after the call. A function is like a black box. It takes inputs,
does something with them, then spits out an answer.

1 # include < stdio .h >

3 void P_Loop ( void ) {


int i ;
5 for ( i = 1; i <= 5; i ++) {
printf ( " % d " , i * i ) ;
7 }
}
9

int main ( void ) {


11 P_Loop () ;
printf ( " \ n " ) ;
13 P_Loop () ;
return 0;
15 }
✆✌
The output is

1 4 9 16 25
1 4 9 16 25
✆✌

1.10.1 Code Optimisation


It is very common that in a program, there are excess lines of script or it has time/memory
consuming algorithm. Ultimately program takes longer time for execution. By using ad-
vance methods of algorithm and script writing we can reduce the size as well as execution
time of the program. It is known as code optimization. In other words, code optimization
is a method of code modification to improve code quality and efficiency. A program may
1.10. PROCEDURES & FUNCTIONS 187

be optimized so that it becomes a smaller size, consumes less memory, executes more
rapidly or performs fewer input/output operations.
Illustrated Example Assume that we have to find all the prime numbers within 1 to
20. We write a program in which each number is divided by all numbers less than to it.
For example, to check whether 19 is a prime or not, it is divided by integers started from
2 to 19 and if any of the divisor returns the zero as remainder then the number 19 is not
prime.

# include < stdio .h >
2 # include < stdlib .h >

4 int main () {
int n , i = 1 , j , m = 0;
6 printf ( " Enter Limit of Prime Number : " ) ;
scanf ( " % d " , & n ) ;
8 while ( i <= n ) {
int k = 0;
10 for ( j = 2; j < i ; j ++) {
if ( i % j == 0) { // line to be optimised
12 k ++;
}
14 }
if ( k == 0) {
16 m ++;
printf ( " % d is a prime number .\ n " , i ) ;
18 }
i ++;
20 }
printf ( " Total % d primes are found .\ n " , m ) ;
22 return 0;
}
✆✌
Another concept is that, if a number, ‘n’, is not divisible by a maximum integer value of
‘n/2’ then it is not divisible by any integers larger ‘n/2’. For example if 19 is not divisible
by maximum integer value of 19/2, ie 9 then 19 never be completely divisible by 10 or
more. By this method we reduce the iteration loops in the program. Above example can
be rewritten as

1 # include < stdio .h >
# include < stdlib .h >
3

int main () {
5 int n , i = 1 , j , m = 0;
printf ( " Enter Limit of Prime Number : " ) ;
7 scanf ( " % d " , & n ) ;
while ( i <= n ) {
9 int k = 0;
for ( j = 2; j <= i /2; j ++) { // line is optimised
11 if ( i % j == 0) {
k ++;
188 Basic C

13 }
}
15 if ( k == 0) {
m ++;
17 printf ( " % d is a prime number .\ n " , i ) ;
}
19 i ++;
}
21 printf ( " Total % d primes are found .\ n " , m ) ;
return 0;
23 }
✆✌
By this way we have reduce the execution time of the program (better performance)
without compromising its output. Again if a number ‘n’ is divisible by ‘2’, above program
checks the divisibility upto maximum integer value of ‘n/2’ by several iteration even if it
was confirm that the number ‘n’ is not prime in first iteration. To enhance the performance
of the program, we can again optimize the code by using break-continue function when
number is checked and confirmed that it is not prime in first iteration.

1 # include < stdio .h >
# include < stdlib .h >
3

int main () {
5 int n , i = 1 , j , m = 0;
printf ( " Enter Limit of Prime Number : " ) ;
7 scanf ( " % d " , & n ) ;
while ( i <= n ) {
9 int k = 0;
for ( j = 2; j <= i / 2; j ++) {
11 if ( i % j == 0) {
k ++;
13 break ; /* no further check that the number *
* is primeif it is declared not a *
15 * prime in first few iterations . */
} else {
17 continue ;
}
19 }
if ( k == 0) {
21 m ++;
printf ( " % d is a prime number .\ n " , i ) ;
23 }
i ++;
25 }
printf ( " Total % d primes are found .\ n " , m ) ;
27 return 0;
}
✆✌
It again enhance the performance of program by multiple times. Similarly, if given number
is even number then it shall never be prime and if given number is odd number then it
shall not be prime if it has a perfect square-root. Again, square-root of odd number is
1.10. PROCEDURES & FUNCTIONS 189

only odd number. It means we have to check the divisibility of given number by all odd
numbers less than or equal to square root of the given number. By this way we can
further optimize the code for prime numbers.

# include < math .h >
2 # include < stdio .h >

4 int main () {
int n = 147853;
6 int x , y = 1;
int sq = sqrt ( n ) + 1;
8 if ( n < 2)
y = 0;
10 if ( n == 2 || n == 3)
y = 1;
12 if ( n % 2 == 0)
y = 0;
14 for ( x = 3; x <= sq ; x += 2) {
if ( n % x == 0)
16 y = 0;
}
18 if ( y == 1) {
printf ( " A prime \ n " ) ;
20 } else {
printf ( " Not A prime \ n " ) ;
22 }
return 1;
24 }
✆✌

Execution Time In good programming practices, codes are written in such manner
that they took least execution time with optimum performance. Using clock () function,
we can get the execution time of the program. A simple example is given below.

# include < stdio .h >
2 # include < stdlib .h >
# include < time .h >
4

int main () {
6 clock_t startTime = clock () ;
int n = 1000000 , i = 1;
8 while ( i <= n ) {
i ++;
10 }
clock_t endTime = clock () ;
12 double td = ( endTime - startTime ) / ( double ) CLOCKS_PER_ SE C ;
printf ( " Program has run for %5.8 f seconds \ n " , td ) ;
14 return 0;
}
✆✌

Program has run for 0.00000200 seconds
✆✌
190 Basic C

Additional to this, some time it is required to know the local time (computer clock time)
for best performance of the program. Here is an example that uses time.h header file to
get the local time. The code line

1 time_t time ( time_t * seconds ) ;
✆✌
returns the time lapsed since the mid night of January 1, 1970, measured in seconds. If
‘seconds’ is not NULL, the return value is also stored in variable ‘seconds’.

1 # include < stdio .h >
# include < time .h >
3

int main () {
5 time_t seconds ;

7 seconds = time ( NULL ) ;


printf ( " Hours since January 1 , 1970 = % ld \ n " , seconds / 3600) ;
9

return (0) ;
11 }
✆✌

Hours since January 1 , 1970 = 405089
✆✌
Another example is

1 # include < time .h >
# include < stdlib .h >
3 # include < stdio .h >

5 int main ( void ) {


time_t current_time ;
7 char * c_time_string ;
int i = 5;
9 while ( i > 0) {
sleep (1) ;
11 /* Obtain current time . */
current_time = time ( NULL ) ;
13 /* Convert to local time format . */
c_time_strin g = ctime (& current_time ) ;
15 printf ( " Current time is %d , % s " , current_time ,
c_time_strin g ) ;
i - -;
17 }
return EXIT_SUCCESS ;
19 }
✆✌

Current time is 1458321446 , Fri Mar 18 22:47:26 2016
Current time is 1458321447 , Fri Mar 18 22:47:27 2016
Current time is 1458321448 , Fri Mar 18 22:47:28 2016
Current time is 1458321449 , Fri Mar 18 22:47:29 2016
1.10. PROCEDURES & FUNCTIONS 191

Current time is 1458321450 , Fri Mar 18 22:47:30 2016


✆✌

Specifier Output Format


%a Short weekday name
%A Full weekday name
%b Short month name
%B Full month name
%c Time stamp
%d Day of the month
%H Hour in 24h format
%I Hour in 12h format
%j Day of the year
%m Month as a decimal number
%M Minutes
%p AM or PM
%S Seconds
%U Week number, first day of first week is Sunday
%w Weekday as a decimal number with Sunday as 0 (0-6)
%W Week number, first day of first week is Monday
%x Date representation
%X Time representation
%y Two digit Year format (00-99)
%Y Four digit Year format
%Z Timezone name
%% A % sign

Table 1.22: Date & time format specifiers.

1.10.2 Increments & Decrements


The character set ‘++’ is used to increase the value by one and −− is used to decrease
the value by one of the variable with which the character set is prefixed or post-fixed.
There are two ways to use these notations. One is ‘++n’ and other is ‘n++’. Both have
same meaning but first is used where value is to be used after one increment while later
is used where value is to be increase by one after using it.
192 Basic C


1 # include < stdio .h >
# include < stdlib .h >
3

int main ( void ) {


5 int i = 0;
printf ( " use of ++ i \ n " ) ;
7 while ( i < 3) {
/* calling & placing at same place . */
9 printf ( " % d = > % d \ n " , i , ++ i ) ;
}
11 printf ( " use of i ++ \ n " ) ;
int j = 0;
13 while ( j < 3) {
printf ( " % d = > % d \ n " , j , j ++) ;
15 }
return EXIT_SUCCESS ;
17 }
✆✌

use of ++ i
1 => 1
2 => 2
3 => 3
use of i ++
1 => 0
2 => 1
3 => 2
✆✌
If increment or decrements is used inside a loop, there are no difference in the use of ‘i++’
or ‘++i’.

# include < stdio .h >
2 # include < stdlib .h >

4 int main ( void ) {


int i = 0;
6 printf ( " Use of i ++ in while loop \ n " ) ;
while ( i < 3) {
8 /* first increment . */
i ++;
10 /* then use . */
printf ( " : - > % d \ n " , i ) ;
12

}
14 printf ( " Use of ++ i in while loop \ n " ) ;
int j = 0;
16 while ( j < 3) {
/* first increment . */
18 ++ j ;
/* then use . */
20 printf ( " : - > % d \ n " , j ) ;
1.10. PROCEDURES & FUNCTIONS 193

22 }
return EXIT_SUCCESS ;
24 }
✆✌

Use of i ++ in while loop
:-> 1
:-> 2
:-> 3
Use of ++ i in while loop
:-> 1
:-> 2
:-> 3
✆✌
This increment operator can not be used in variable initialization or with constants like
3 + + or directly in output stream functions like printf. The following type of syntax are
illegal.

int i =2++; // illegal coding
2 printf ( " Increment of 2 is % d \ n " ,2++) ; // illegal coding
✆✌
The same methods can be used for decrements operator. In increments or decrements
operations, value of variable i is incremented by one and then the result is assigned to
variable i. This is why, constant values can not be used with this unary operator, i.e.
5 + + and + + 5 cause compile time errors. See another example for i + + and + + j
unary operators.

# include < stdio .h >
2

int main ( int argc , char ** argv ) {


4 int i = 0;
while ( i < 3) {
6 printf ( " i is % d \ n " , i ++) ; /* started from 0 */
}
8 printf ( " \ n " ) ;
int j = 0;
10 while ( j < 3) {
printf ( " j is % d \ n " , ++ j ) ; /* started from 1 */
12 }
return 0;
14 }
✆✌

i is 0
i is 1
i is 2

j is 1
j is 2
j is 3
✆✌
194 Basic C

Again, before summing up this section, always remember that k + 1 and k + + results
increment of variable ‘k’ by one. But first expression is purely different to second ex-
pression. In first expression, the value of ‘k’ remains unchanged only results reflects to
increment by one, while in second expression, value of ‘k’ is incremented by one and again
assigned to it.

1 # include < stdio .h >

3 int main ( int argc , char ** argv ) {


int k = 0 , l = 0;
5 printf ( " k +1 is % d and l ++ is % d \ n " , k +1 , l ++) ;
printf ( " k +1 is % d and l ++ is % d \ n " , k +1 , l ++) ;
7 printf ( " k +1 is % d and l ++ is % d \ n " , k +1 , l ++) ;
return 0;
9 }
✆✌

k +1 is 1 and l ++ is 0
k +1 is 1 and l ++ is 1
k +1 is 1 and l ++ is 2
✆✌
When increment and decrements operators are used simultaneously, then increment and
decrements is performed simultaneous in order.

1 # include < stdio .h >
# include < stdlib .h >
3

int myF ( int i ) {


5 int j = 1 , re , r = 2;
while ( j < i ) {
7 re = ( r ++) *(++ r ) ; // re = (2) * (4) ; r = 4;
j ++;
9 }
return re ;
11 }

13 int main () {
int i = 5 , j = 3;
15 printf ( " % d " , myF (5) ) ;

17 return 0;
}
✆✌

80
✆✌
In above program, in each loop, first value of r in r + + is used and then it is incremented.
The value of r in ++r is incremented and then used. Therefore, in first loop, the equivalent
expression shall be

1 re = (2) * (4) ;
✆✌
1.10. PROCEDURES & FUNCTIONS 195

And for next loop, the new value of r is 4. In case of increment operator is used with
array elements like

1 a [ i ]= i ++;
✆✌
In this case, initial value of ‘i’ is taken and incremented by one. This original value
is stored as element of array ‘a’, at index position given by incremented ‘i’, i.e. ‘i+1’.
Actually, for any value of ‘i’ above expression becomes

1 a [ i +1]= i ;
✆✌
See the example below

1 # include < stdio .h >

3 int main ( int argc , char * argv []) {


int i = 80;
5 int j = i ;
char a [100];
7 /* In following expression , first value of i *
* is used and then it is incremented . Value *
9 * of i stored at array element as a [ i ++]= i */
a [ i ] = i ++;
11 /* Actual i and equivalent char */
printf ( " % d = >% c \ n " , j , j ) ;
13 /* Values stored in array as its *
* element for initial i values */
15 printf ( " a [% d ]=% c \ n " , j , a [ j ]) ;
/* Actual array element values */
17 printf ( " a [% d ]=% c \ n " , i , a [ i ]) ;
return 0;
19 }
✆✌

80= > P
a [80]=(
a [81]= P
✆✌
Again see the following example, in which we try to get the result 110 by multiplying
increment operators.

1 # include < stdio .h >

3 int main ( int argc , char * argv []) {


int i = 10;
5 printf ( " % d \ n " , i ++ * i ++) ;
return 0;
7 }
✆✌

100
✆✌
196 Basic C

But actual result is 100 rather than 110. It means after using the current value of ‘i’, ‘i’
does not goes increment for next use of ‘i’. It reason is that, C does not guaranteed to
increment the value of ‘i’ just after using it but it increments value of ‘i’ sometime before
the expression is considered “finished” or just before the next “sequence point”.

1.10.3 Static Function


In a program, if a function is declared as static then it can only be called from the same
file in which it is declared. It can not called from the other files. The syntax of static
function is

1 static int compare ( int a , int b ) {
return ( a + 4 < b ) ? a : b ;
3 }
✆✌
An example of static function is

1 # include < stdio .h >

3 static int compare ( int a , int b ) {


return ( a > b ) ? a : b ;
5 }

7 int main () {
int j ;
9 j = compare (2 , 4) ;
printf ( " : - > % d .\ n " , j ) ;
11 return 0;
}
✆✌

: - > 4.
✆✌

1.10.4 Function with Variable Arguments


A static function can be called by its prototype. Normally in static functions number
of arguments remain fix but variable number of arguments can also be passed to the
function. Calling of a function with variable arguments is given in following example.

1 # include < stdlib .h >

3 # define MAXARGS 3
int var_arg () ;
5

int main () {
7 var_arg (1 , 2 , 3) ;
return 0;
9 }

11 int var_arg ( int a ) {


1.10. PROCEDURES & FUNCTIONS 197

int i = 0;
13 while ( i < MAXARGS ) {
printf ( " % d argument is % d .\ n " , i , (& a ) [ i ]) ;
15 i ++;
}
17 return a ;
}
✆✌
A ‘var arg’ function is defined in prototype as null variables

int var_arg () ;
✆✌
This prototype function is defined as single argument list.

1 int var_arg ( int a )
✆✌
When function is called with three integer arguments, this argument list is passed to the
function definition as a list.

1 var_arg (1 , 2 , 3) ;
✆✌
Following line in the program

1 printf ( " % d argument is % d .\ n " , i , (& a ) [ i ]) ;
✆✌
prints the each element of the variable list of ‘a’. Second method uses macros defined in
the header file <stdarg.h>.

1 # include < stdio .h >
# include < stdarg .h >
3

void varStrings ( const char *f , ...) {


5 int max_args = 5;
va_list args ;
7 va_start ( args , max_args ) ;
printf ( " % s \ n " , f ) ;
9 while ( max_args - -)
puts ( va_arg ( args , const char *) ) ;
11 va_end ( args ) ;
}
13

int main () {
15 varStrings ( " f " , " Mary " , " had " , " a " , " little " , " lamb " ) ;
return 0;
17 }
✆✌
The syntax variable argument function requires at least one fixed argument before the
‘...’. Here ‘va list’ creates memory for the variable list ‘valist’. ‘va start’ function accepts
arguments and stores in the variable list ‘valist’ memory. ‘va arg’ function returns the
variable value from variable list ‘valist’. ‘va end’ function cleans the memory reserved
for valist. In pursuance to standard method of programming, in a function with variable
198 Basic C

arguments, first argument/element should be an integer, representing the number of ar-


guments to be passed to the function. In following example, sum of integers by passing
variable arguments is obtained.

1 # include < stdarg .h >

3 int sum ( int num , ...) {


va_list ap ;
5 int total = 0;
va_start ( ap , num ) ;
7 while ( num > 0) {
total += va_arg ( ap , int ) ;
9 num - -;
}
11 va_end ( ap ) ;
return total ;
13 }

15 int main () {
/* First argument determines the number of **
17 ** following arguments , those shall be used **
** in the sum function . Here it is 5. */
19 int a = sum (5 , 1 , 2 , 3 , 4 , 6) ;

21 /* First argument determines the number of **


** following arguments , those shall be used **
23 ** in the sum function . Here it is 2. */
int b = sum (2 , 3 , 5 , 8) ;
25 printf ( " Sums are % d and % d \ n " , a , b ) ;
return 0;
27 }
✆✌

Sums are 16 and 8 respectively .
✆✌

1.10.5 Indirect Call of Function


In C, the input is considered as string even though input contains the name of inbuilt
functions or operators. For example, input “sin(90)” is considered as string which is a
group of ‘s’, ‘i’, ‘n’, ‘(’, ‘9’, ‘0’, ‘)’ and NULL characters rather than sine operator on
operand ‘90’. Using indirect call of a function, we can execute a function by supplying
function name as string input.

1 # include < stdio .h >
# include < stdlib .h >
3 # include < math .h >

5 double Equ1 ( double x ) {


return x ;
7 }
1.10. PROCEDURES & FUNCTIONS 199

9 double Equ2 ( double x ) {


return x * x ;
11 }

13 double Equ3 ( double x ) {


return log ( x ) ;
15 }

17 typedef double (* Eqn ) ( double ) ;

19 int main () {
int i ;
21 double ic ;

23 const char * EqnNames [3] = {


" Equ1 " , " Equ2 " , " Equ3 "
25 };
Eqn FEqu [ ] = { Equ1 , Equ2 , Equ3 };
27

for ( i = 0; i < ( sizeof ( FEqu ) / sizeof ( Eqn ) ) ; i ++) {


29 ic = (* FEqu [ i ]) ( i + 1) ;
printf ( " Eqn Name = %5 s : a =% d : Result =% lf \ n " ,
31 EqnNames [ i ] , i + 1 , ic ) ;
}
33 return 0;
}
✆✌

Eqn Name = Equ 1 : a =1 : Result =1.000000
Eqn Name = Equ 2 : a =2 : Result =4.000000
Eqn Name = Equ 3 : a =3 : Result =1.098612
✆✌

1.10.6 Preprocessor Macros


Preprocessors are used to define macros or manifest constants and are included in the
header of source file. Preprocessors can be defined separately in a file having extensions
‘.h’ or in the same source file. Some of the useful pre-processors are explained below.

Literals
The token reserved for the preprocessor is the octothorp, #, and the preprocessor makes
three entirely different uses of it. Using, this token we can put the macros within the
function. Whitespace before the # is ignored. Next use of # in a macro makes input a
string, known as compound literal. See the example below:

1 # include < stdio .h >
# define myMacro ( v ) printf (# v " : % d \ n " , v ) ;
3

int main () {
200 Basic C

5 myMacro (10 / 5) ;
myMacro (15 / 5) ;
7 return 0;
}
✆✌

10 / 5 : 2
15 / 5 : 3
✆✌

Tokens
Body of a macro is considered as a string of tokens rather than a string of characters. C
preprocessor tokens are the separate “words” in the body of a macro definition. They are
separated from one another by white spaces. For example, the definition

# define FOUR 2*2
✆✌
has one token-the sequence 2*2, but the definition

1 # define SIX 2 * 3
✆✌
has three tokens 2, *, and 3. Character, strings and token strings differ from each other.
It depends on how how multiple spaces are treated in a macro body. The preprocessor
doesn’t make calculations; it just substitutes strings. For example

1 # include < stdio .h >

3 # define SQUARE ( X ) X * X

5 int main ( void ) {


int x = 4;
7 printf ( " x = % d \ n " , x ) ;
printf ( " SQUARE ( x ) : % d " , SQUARE ( x ) ) ;
9

/* Above statement is equivalent to *


11 * printf (" SQUARE ( x ) : % d " , x * x ) ; */
return 0;
13 }
✆✌

x = 4
SQUARE ( x ) : 16
✆✌
In above example value of ‘x’ is passed to predefined function ‘SQUARE(X)’ and the
function replaces ‘X’ by ‘x’ as ‘x*x’ and ultimately ‘4*4’. Now the result is ‘16’. If the
‘x’ passed to the function as shown in the given example then

# include < stdio .h >
2

# define SQUARE ( X ) X * X
1.10. PROCEDURES & FUNCTIONS 201

int main ( void ) {


6 int x = 2;
printf ( " x = % d \ n " , x ) ;
8 printf ( " SQUARE ( x ) : % d " , SQUARE ( x +2) ) ;

10 /* above statement is equivalent to *


* printf (" SQUARE ( x ) : % d " , x +2* x +2) ; */
12 return 0;
}
✆✌

x = 2
SQUARE ( x ) : 8
✆✌
Result is ‘8’ rather than predicted as ‘16’. The reason behind it is that when ‘x+2’ is
passed to the function ‘SQUARE’, it replaces ‘X*X’ by ‘x+2’ as ‘x+2*x+2’ and it gives
the ultimately result ‘2+2*2+2’ that is ‘8’. Again

# include < stdio .h >
2

# define SQUARE ( X ) X * X
4

int main ( void ) {


6 /* Initial declaration of x =2. */
int x = 2;
8

/* x =2 */
10 printf ( " x = % d \ n " , x ) ;

12 /* In below line , x in incremented *


* by 1 and it becomes x =2+1=3 before *
14 * it passes to macro SQUARE () . */
printf ( " SQUARE ( x ) : % d " , SQUARE (++ x ) ) ;
16

/* Above statement is equivalent to *


18 * printf (" SQUARE ( x ) : % d " , ++ x *++ x ) ;*
* Here again x is incremented by 1 *
20 * from its previous declaration *
* and it becomes x =3+1=4. */
22 return 0;
}
✆✌

x = 2
SQUARE ( x ) : 16
✆✌

#if, #else, #elif, #endif


These are also known as conditionals. The #if checks whether a controlling condition
expression evaluates to zero or nonzero, and excludes or includes a block of code respec-
202 Basic C

tively.

# if 1
2 /* This block will be included */
# endif
4 # if 0
/* This block will not be included */
6 # endif
✆✌
A simple example is

# include < stdio .h >
2 /* Define row size 80 */
# define RSIZE 80
4 /* If row size is >200 set row size 200 */
# if RSIZE > 200
6 # undef RSIZE
# define RSIZE 200
8 /* else if row size is <50 set row size 50 */
# elif RSIZE <50
10 # undef RSIZE
# define RSIZE 50
12 /* Else set row size 100 :: it is true */
# else
14 # undef RSIZE
# define RSIZE 100
16 # endif
int main () {
18 printf ( " The row size is % d .\ n " , RSIZE ) ;
do_A () ;
20 return 0;
}
22 /* Define row size 201 */
# define RSIZE_B 201
24 /* If row size is >200 set row size 200 :: It is true */
# if RSIZE_B > 200
26 # undef RSIZE_B
# define RSIZE_B 200
28 /* else if row size is <50 set row size 50 */
# elif RSIZE_B <50
30 # undef RSIZE_B
# define RSIZE_B 50
32 /* Else set row size 1001 */
# else
34 # undef RSIZE_B
# define RSIZE_B 100
36 # endif

38

do_A () {
40 printf ( " The row size is % d .\ n " , RSIZE_B ) ;
}
1.10. PROCEDURES & FUNCTIONS 203

✆✌

The row size is 100.
The row size is 200.
✆✌

#ifdef & #ifndef


The #ifdef is similar to #if, except that the code block following it is selected if a macro
name is defined. In this respect,

# ifdef NAME
✆✌
is equivalent to

1 # if defined NAME
✆✌
A simple example is

1 # include < stdio .h >
# ifndef __cplusplus
3 # error A C ++ compiler is required !
# endif
5

int main () {
7 printf ( " C ++ compiler needed !!! " ) ;
return 0;
9 }
✆✌
The #ifndef is similar to #ifdef, except that the test is reversed:

1 # ifndef NAME
✆✌
is equivalent to

1 # if ! defined NAME
✆✌
A simple example is

1 # include < stdio .h >
# ifndef A
3 # define A 10
# endif
5

int main () {
7 printf ( " : - > % d .\ n " , A ) ; // printed "10"
return 0;
9 }
✆✌

: - > 10.
✆✌
204 Basic C

#define
#define is used to define a preprocessor with known value. The syntax for this prepro-
cessor is

1 # define < identifier > < token - string >
✆✌
A program written in C is known as macro. When the computer reads the code, it
replaces all instances of a word with the specified expression. #define macro is used for
this purpose.

1 # define PRICE _ OF _ PEN 5
✆✌
When ever we want to print the price of pen, we use the word PRICE OF PEN instead of
the number 5, preprocessor will replace all instances of PRICE OF PEN with 5, which the
compiler will interpret as the literal integer 5. The preprocessor performs substitution,
that is, PRICE OF PEN is replaced by 5. Increments or decrements operation are not
allowed with preprocessor identifier. For example

1 PRICE_OF_PEN ++ /* equals to 5++ */
/* OR */
3 ++ PRICE_OF_PEN /* equals to ++5 */
✆✌
are illegal and not allowed. Because above operation becomes

1 5++
/* OR */
3 ++5
✆✌
and these are illegal in C. It means there is no need for a semicolon. The # and ##
operators are used with the #define macro. Using # causes the first argument after the
# to be returned as a string in quotes. For example, the function

1 # define as_string ( s ) # s
✆✌
will make the compiler turn this function

1 puts ( as_string ( Hello World ! ) ) ;
✆✌
into

1 puts ( " Hello World ! " ) ;
✆✌

1 # include < stdio .h >
# include < string .h >
3 # define as_string ( s ) # s

5 int main () {
puts ( as_string ( Hello World !!!!) ) ;
7 return 0;
}
✆✌
1.10. PROCEDURES & FUNCTIONS 205


Hello World !!!!
✆✌
Symbol ## concatenates what is before the ## with what is after it. After concate-
nation, strings becomes tokens. For example, in the following code snippets, function
‘concatenate’ converts two strings passed without double quotes, say x and y into token
xy.

1 # define concatenate ( a , b ) a ## b
...
3 int xy = 10;
...
✆✌
When this preprocessor is called from anywhere as shown in the below code line,

printf ( " % d " , concatenate ( x , y ) ) ;
✆✌
compiler turns this code line as

1 printf ( " % d " , xy ) ;
✆✌
which will, of course, display 10 in the standard output.

1 # include < stdio .h >
# include < string .h >
3 # define concatenate ( a , b ) a ## b

5 int main () {
int xy = 10;
7 printf ( " % d " , concatenate (x , y ) ) ;
return 0;
9 }
✆✌

10
✆✌
It is possible to concatenate a macro argument with a constant prefix or suffix to obtain
a valid identifier as in

1 # define make_function ( name ) int my_ ## name ( int foo ) {}
make_function ( bar )
✆✌
which will define a function called my bar(). But it isn’t possible to integrate a macro
argument into a constant string using the concatenation macro. In order to obtain such an
effect, one can use the ANSI C property that two or more consecutive string constants are
considered equivalent to a single string constant when encountered. Using this property,
one can write

# define eat ( what ) puts ( " I ’m eating " # what " today . " )
2 eat ( fruit )
✆✌
206 Basic C

which the macro-processor will turn into



puts ( " I ’ m eating " " fruit " " today . " )
✆✌
which in turn will be interpreted by the C parser as a single string constant. The following
trick can be used to turn a numeric constants into string literals

1 # define num2str ( x ) str ( x )
# define str ( x ) # x
3 # define CONST 23
puts ( num2str ( CONST ) ) ;
✆✌
This is a bit tricky, since it is expanded in 2 steps. First ‘num2str(CONST)’ is replaced
with str(23), which in turn is replaced with “23”.

# include < stdio .h >
2 # include < string .h >
# define num2str ( x ) str ( x )
4 # define str ( x ) # x
# define CONST 23
6

int main () {
8 puts ( num2str ( CONST ) ) ;
return 0;
10 }
✆✌

23
✆✌
Using of catecanation symbol ‘##’ is useful when we have to create different user defined
functions with same signature of function which are being called through their pointer
addresses. See the example below, in which we have create a function by using ‘##’
symbol.

1 # include < stdio .h >

3 # define init_fcn ( name , type ) \


/* Create structure for object ‘ age ’ */ \
5 typedef struct \
{ \
7 type value ; \
} F ## name ; \
9 /* Create mf_age function */ \
inline F ## name mf_ ## name ( type v ) \
11 { \
F ## name t ; \
13 t . value = v ; \
return t ; \
15 }

17 int main () {
init_fcn ( age , int ) ;
1.10. PROCEDURES & FUNCTIONS 207

19 init_fcn ( Roll , int ) ;


printf ( " % d \ n " , mf_age (20) ) ;
21 printf ( " % d \ n " , mf_Roll (1020) ) ;
return 0;
23 }
✆✌

20
1020
✆✌
A macro assigned with a numerical value using #define preprocessor can be assessed
from anywhere in the program. But it can not be assigned new value within the pro-
gram. To change the assigned value to a macro, it should be redefined by using #define
preprocessor.

# include < stdarg .h >
2 # define MAX_NO 100

4 int main () {
printf ( " Maximum Nos is % d .\ n " , MAX_NO ) ;
6 # define MAX_NO 10
printf ( " Maximum Nos is % d .\ n " , MAX_NO ) ;
8 MAX_NO =50; // Illegal assignment . Shows error
printf ( " Maximum Nos is % d .\ n " , MAX_NO ) ;
10 return 0;
}
✆✌
Example for preprocessor #define is given below

1 # include < stdio .h >
# define getmax (a , b ) (( a ) >( b ) ?( a ) :( b ) )
3

int main () {
5 int y ;
y = getmax (5 , 2) ;
7 printf ( " The max value is % d . " , y ) ;
return 0;
9 }
✆✌

The max value is 5.
✆✌
Use of #define function must be used carefully when the defined value is to be used in
mathematical expression. See the example below:

1 # include < stdio .h >
# define PI 3.142857143 /* First form of defining macro . */
3

int main () {
5 double i = 2 * PI / 3;
printf ( " i is % lf " , i ) ;
7 return 0;
208 Basic C

}
✆✌
The expression line of above example

double i = 2 * PI / 3;
✆✌
The ‘PI’ is replaced by the macro value ‘3.14’ as

1 double i = 2 * 3.142857143 / 3;
✆✌
And the program gives result

i is 2.095238
✆✌
Now, see the example shown below, in which the ‘PI’ macro value is changed in rational
form even though its numerical value is same.

1 # include < stdio .h >

3 # define PI 22 / 7 /* Rational form . */


/* Here , 22/7 is equal to 3 numerically */
5

int main () {
7 double i = 2 * PI / 3;
printf ( " i is % lf " , i ) ;
9 return 0;
}
✆✌
This form of defining a value is wrong. See the reason in following lines. Assume that,
‘PI’ is defined as shown below

# define PI 22 / 7
✆✌
When preprocessor is replaced by its expression, the expression i becomes as

1 double i = 2 * PI / 3;
✆✌
At the time of compilation, preprocessor value of PI is used as 3 rather than 3.142857143.
Now, the value of i becomes

1 double i = 2 * 3 / 3;
✆✌
On solving this expression, the final result thus obtained is 2, which is not what we
expected.

i is 2.000000
✆✌
For desired output, proprocessor PI should be defined as (f loat)22/7 instead of 22/7.
See the modified form of above example.
1.10. PROCEDURES & FUNCTIONS 209


1 # include < stdio .h >

3 # define PI ( float ) 22 / 7

5 int main () {
double i = 2 * PI / 3;
7 printf ( " i is % lf " , i ) ;
return 0;
9 }
✆✌

i is 2.095238
✆✌
The preprocessors may be defined either before or after the header inclusion. In both
cases, output is same.

1 # define NOS 10

3 # include < stdio .h >

5 int main () {
printf ( " % d " , NOS ) ;
7 }
✆✌

10
✆✌
ANSI C defines some useful preprocessor macros and variables, also called “magic con-
stants”.

1 __ FILE __ = > The name of the current file , as a string literal .
__ LINE __ = > Current line of the source file , as a numeric literal .
3 __ DATE __ = > Current system date , as a string .
__ TIME __ = > Current system time , as a string .
5 __ TIMESTAMP __ = > Date and time ( non - standard ) .
__ cplusplus = > undefined when your C code is being compiled by a C
compiler .
7 __ func __ = > Current function name of the source file , as a string .
✆✌
A simple example for using of preprocessors is derived in three parts. Main part, sum
part and preprocessors for sum part. Following is the code of ‘sum.h’ preprocessor

1 # ifndef SUM_H
# define SUM_H
3 # ifdef __cplusplus
extern " C " {
5 # endif
/* function identifier for sum_f () defined in sum . c */
7 int sum_f ( int a , int b ) ;
# ifdef __cplusplus
9 }
210 Basic C

# endif
11 # endif /* SUM_H */
✆✌
Codes of sum function is define in the file ‘sum.c’.

1 /* sum_f () function for adding two numbers */
int sum_f ( int a , int b ) {
3 int c ;
c = a + b;
5 return c ;
}
✆✌
Main function for calling a procedure is defined in ‘main.c’ file as

# include < stdio .h >
2 /* sum . h header contains sum_f () function *
* that should be indentified and called . */
4 # include " sum . h "

6 int main ( void ) {


int a =2 , b =3;
8 /* sum_f () function is called from *
* sum . c and identified via sum . h */
10 int c = sum_f (a , b ) ;
printf ( " The sum of 2 and 3 is % d . " ,c ) ;
12 return 0;
}
✆✌
When program is compiled and run the output is

The sum of 2 and 3 is 5.
✆✌
If a macro produces multiple statements, or declares variables, it can be wrapped in
a do { ... } while(0) loop, with no terminating semicolon. This allows the macro to be
used like a single statement in any location.

1 # define FREE ( p ) free ( p ) ; p = NULL ; /* Bad practice . */
# define FREE ( p ) do { free ( p ) ; p = NULL ; } while (0) /* Good
practice . */
✆✌

1.10.7 Type Converter


Following is an example of string to integer conversion.

# include < stdio .h >
2 # include < string .h >

4 int main ( int argc , char * argv [ ]) {


char st [10] = " This " ;
6 printf ( " String ’% s ’ = integer % d .\ n " , st , ( int ) st ) ;
1.11. PARSING ARGUMENTS 211

return 0;
8 }
✆✌

String ’This ’ = integer 2280640.
✆✌

1.11 Parsing Arguments


When a program is being executed via another program internally, arguments are required
to be passed to the executable ie the program. These arguments are considered as inputs
for the executable. To pass the values we define main() function as

1 int main ( int argc , char * argv [ ])
✆✌
Here argc counts the number of arguments in an array and argv assigns the values to
each respective counter.

1 # include < stdio .h >
# include < string .h >
3 # include < stdlib .h >

5 /* main function is modified according to *


* receive the arguments in command line */
7 int main ( int argc , char * argv [ ]) {
int argnum = 0;
9 /* Starting from zero */
while ( argc > ++ argnum )
11 printf ( " Argument % d of arguments % d is % c .\ n " ,
argnum ,
13 argc ,
* argv [ argnum ]) ;
15 exit ( EXIT_SUCCESS ) ;
}
✆✌
After compiling and executing the executable as

executable . exe a b c
✆✌
Output is

Argument 1 of supplied four arguments is a .
Argument 2 of supplied four arguments is b .
Argument 3 of supplied four arguments is c .
✆✌
Here executable.exe in command-line is also considered as an argument. This is why
there are four arguments and first argument, ie 0th argument, is executable.exe itself and
rest of the arguments are a, b and c respectively. An other example is given below
212 Basic C


1 # include < stdio .h >

3 int main ( int argc , char ** argv ) {


size_t i ;
5

for ( i = 0; i < argc ; i ++) {


7 /* get all the arguments as options *
* and initialize option pointer . */
9 char const * option = argv [ i ];
/* Get first character of an option argument */
11 if ( option [0] == ’ - ’) {
/* If first character of an option argument *
13 * is ’-’, then following character is a flag */
printf ( " Flagged option .\ n " ) ;
15 /* get the second character of an option argument . */
switch ( option [1]) {
17 /* If second char of an option argument *
* is ’e ’, then print encryption */
19 case ’e ’:
printf ( " You have chosen % c : ENCryption . \ n " ,
option [1]) ;
21 break ;
/* If second char of an option argument *
23 * is ’d ’, then print decryption */
case ’d ’:
25 printf ( " You have chosen % c : DECryption . \ n " ,
option [1]) ;
break ;
27 /* If second char of an option argument *
* is ’f ’, then print filename */
29 case ’f ’:
printf ( " Your have chosen file name % c .\ n " ,
option [1]) ;
31 break ;
/* other wise */
33 default :
printf ( " I can not understand your option % s \ n " ,
option ) ;
35 break ;
}
37 } else {
printf ( " No Flagged Options .\ n " ) ;
39 }
}
41 return 0;
}
✆✌
When above example is compiled and executed like

executable . exe -e -f
✆✌
1.11. PARSING ARGUMENTS 213

The output at console is



No Flagged Option .
Flagged Option .
You have chosen e : ENCryption .
Flagged Option .
You have chosen filename f .
✆✌
The first output “No Flagged Option” is appeared at the console at first as ‘exe-
cutable.exe’ is considered as first parsing argument and it is not prefixed with ‘–’. Using
array and pointer we do reverse to a parsed string via command line is given below.

1 # include < stdio .h >
# include < stdlib .h >
3 /* String Length */
# define SLen 4
5

int main ( int argc , char * argv [ ]) {


7 /* Get the commandline string */
char * name = argv [1];
9 char nameR [10];
int i ;
11 for ( i = 0; i < SLen ; i ++)
/* Store each character of string in array */
13 nameR [ i ] = name [ i ];

15 for ( i = 4; i > 0; -- i )
/* Print each character of stored string in array */
17 printf ( " % c " , nameR [ i - 1]) ;
exit ( EXIT_SUCCESS ) ;
19 }
✆✌
Similarly the string length of given string can also be obtain by using following example

1 # include < stdio .h >

3 int main ( int argc , char * argv [ ]) {


if ( argv [1] == NULL ) {
5 printf ( " Use < utility . exe > < string in quote or double
quote >.\ n " ) ;
exit (0) ;
7 }
/* Get the commandline string */
9 char * name = argv [1];
int i = 0;
11 while ( name [ i ] != NULL )
i ++;
13 printf ( " The length of string is % d " , i ) ;
return 0;
15 }
✆✌
214 Basic C

1.11.1 Array To Integer


atoi() function is used to convert an array into integer. This function is very useful for
the conversion of number arguments passed as array or pointer into integer value. The
use of syntax is explained in the following example.

1 # include < stdio .h >
# include < stdlib .h >
3

int main ( int argc , char * argv [ ]) {


5 if ( argv [1] == NULL ) {
printf ( " Use < utility . exe > < string >.\ n " ) ;
7 exit (0) ;
}
9 int i ;
i = atoi ( argv [1]) ;
11 printf ( " Array to integer is % d . " , i ) ;
exit ( EXIT_SUCCESS ) ;
13 }
✆✌
Without atoi(), we can also convert an array into integer by using simple mathematics
as explained in the following example.

1 # include < stdio .h >

3 int main () {
char intg [ ] = " 1234 " ;
5 int i = 0 , res = 0;
/* Here res must be initialized . Otherwise *
7 * product of res and 10 shall be null value */
while ( intg [ i ] != ’ \0 ’) {
9 /* Product of res with 10. res must not be null .*
* ( intg [ i ] % 48) is used to convert integer *
11 * charcode into integer value . Charcode of 0 is *
* 48. Similarly , charcode of 1 is 49 and so on */
13 res = res * 10 + ( intg [ i ] % 48) ;
i ++;
15 }
printf ( " % d \ n " , res ) ;
17 return 0;
}
✆✌

1234
✆✌
We can also used pointers for array to integer conversion. Above example is modified as
it is given below:

1 # include < stdio .h >

3 int main () {
char * intg = " 1234 " ;
1.12. MATHEMATIS 215

5 int i = 0 , res = 0;
/* Here res must be initialized . Otherwise *
7 * product of res and 10 shall be null value */
while (* intg != ’ \0 ’) {
9 /* Product of res with 10. res must not be null .*
* ( intg [ i ] % 48) is used to convert integer *
11 * charcode into integer value . Charcode of 0 is *
* 48. Similarly , charcode of 1 is 49 and so on */
13 res = res * 10 + (* intg % 48) ;
intg ++;
15 }
printf ( " % d \ n " , res ) ;
17 return 0;
}
✆✌
atoi() function is used to convert an integer array into integer value. Integer value “1234”
as string is stored in memory as a group of characters. Each character is one byte long.

Value at byte : 1 2 3 4
i: 00000001 00000010 00000011 00000100

Integer value “1234” in numeric form is stored in 4 bytes long memory space, allocated
for solely storing of integer.

Num value : 1234


i: 00000000 00000000 00000100 11010010

1.12 Mathematis
In C programming addition, subtraction, multiplication and division mathematical op-
erators can be directly used. Modulus is another mathematical operators that gives the
remainder value. Application of these operators are a + b, a − b, a ∗ b, a/b and a%b
respectively.

# include < stdio .h >
2 # include < string .h >
int a , b ;
4

int main ( void ) {


6 int a = 5;
int b = 2;
8 int add = a + b ;
int sub = a - b ;
10 int mul = a * b ;
int div = a / b ;
12 int mod = a % b ;
216 Basic C

printf ( " Addition of % d and % d is : % d \ n " , a , b , add ) ;


14 printf ( " Subtraction of % d and % d is : % d \ n " , a , b , sub ) ;
printf ( " Multiplicati on of % d and % d is : % d \ n " , a , b , mul ) ;
16 printf ( " Division of % d and % d is : % d \ n " , a , b , div ) ;
printf ( " Modulus of % d and % d is : % d \ n " , a , b , mod ) ;
18 return 0;
}
✆✌
Output of above program is

Addition of 5 and 2 is : 7
Subtraction of 5 and 2 is : 3
Multiplicat io n of 5 and 2 is : 10
Division of 5 and 2 is : 2
Modulus of 5 and 2 is : 1
✆✌
A pointer can also be used in the addition, subtraction, multiplication and division of
two or more numbers.

1 # include < stdio .h >

3 func ( int * i , int * j ) {


*i = *i * *i;
5 *j = *j* *j;
}
7

main () {
9 int i = 5 , j = 2;
func (& i , & j ) ;
11 printf ( " % d % d " , i , j ) ;
return 0;
13 }
✆✌

25 , 4
✆✌

1.12.1 Trigonometric Functions


“math.h” preprocessor file provides the mathematical functions that can be used directly
in the program. Some of them are defined in following sections.

cos, sin & tan


The cos, sin, and tan functions return the cosine, sine, and tangent of the argument,
expressed in radians. The domain of arguments of sin, cos and tan are [−π/2, π/2], [0, π]
and [−π/2, π/2] respectively. The numerical range of sin, cos and tan are [−1, 1], [−1, 1]
and [−∞, ∞].

1 # include < math .h >
double cos ( double x ) ;
1.12. MATHEMATIS 217

3 double sin ( double x ) ;


double tan ( double x ) ;
✆✌
A simple example is

# include < stdio .h >
2 # include < math .h >

4 int main ( void ) {


printf ( " Cosine at 22/7 radian is : % f \ n " , cos (22/7) ) ;
6 printf ( " Sine at 22/7 radian is : % f \ n " , sin (22/7) ) ;
printf ( " Tangent at 22/7 radian is : % f \ n " , tan (22/7) ) ;
8 return 0;
}
✆✌

Cosine at 22/7 radian is : -0.989992
Sine at 22/7 radian is : 0.141120
Tangent at 22/7 radian is : -0.142547
✆✌

Solved Problem 1.8 A right angle triangle having base 20cm and height h. The angle of
triangle facing to side h is 30◦ , then find the height of the triangle.

Solution We know that in right angle triangle, one angle is 90◦ . If angle facing to the
side of hcm is 30◦ then
h h
tan 30◦ = =
b 20

It gives, the height of the triangle h = 20/ 3cm.

1 # include < stdio .h >
# include < math .h >
3 # define PI 3.14

5 double DtoR ( int x ) {


return x * PI / 180;
7 }

9 int main () {
double h ;
11 double b = 20.0;
int th = 30; /* in degree */
13 h = b * tan ( DtoR ( th ) ) ;
printf ( " The height of the triangle is % lf " , h ) ;
15 return 0;
}
✆✌

The height of the triangle is 11.539928
✆✌
218 Basic C

acos, asin & atan


The acos() functions return the arccosine of their arguments in radians, and the asin()
functions return the arcsine of their arguments in radians. All functions expect the
argument in the range [−1, +1]. The h arccosine returns a value in the range [0, π]; the
π πi
arcsine returns a value in the range − , . The atan() returns their argument value
h π πi 2 2
in radian in the range − , . Method of use of inverse function in following systems.
✞ 2 2
1 # include < math .h >
double asin ( double x ) ;
3 double acos ( double x ) ;
double atan ( double x ) ;
✆✌
A simple example is

# include < stdio .h >
2 # include < math .h >

4 int main ( void ) {


printf ( " Arc cosine at argument 0.5 is : % f \ n " , acos (0.5) ) ;
6 printf ( " Arc sine at argument 0.5 is : % f \ n " , asin (0.5) ) ;
printf ( " Arc tangent at argument 1.5 is : % f \ n " , atan (1.5) ) ;
8 return 0;
}
✆✌

Arc cosine at argument 0.5 is : 1.047198
Arc sine at argument 0.5 is : 0.523599
Arc tangent at argument 1.5 is : 0.982794
✆✌

cosh, sinh & tanh


The cosh(), sinh() and tanh() functions compute the hyperbolic cosine, the hyperbolic
sine and the hyperbolic tangent of the argument respectively.

1 # include < math .h >
double cosh ( double x ) ;
3 double sinh ( double x ) ;
double tanh ( double x ) ;
✆✌
A simple example is

# include < stdio .h >
2 # include < math .h >

4 int main ( void ) {


printf ( " Hyperbolic cosine of 0.5 is : % f \ n " , cosh (0.5) ) ;
6 printf ( " Hyperbolic sine of 0.5 is : % f \ n " , sinh (0.5) ) ;
printf ( " Hyperbolic tangent of 1.5 is : % f \ n " , tanh (1.5) ) ;
8 return 0;
1.12. MATHEMATIS 219

}
✆✌

Hyperbolic cosine at argument 0.5 is : 1.127626
Hyperbolic sine at argument 0.5 is : 0.521095
Hyperbolic tangent at argument 1.5 is : 0.905148
✆✌

acosh, asinh & atanh


The acosh() functions compute the inverse hyperbolic cosine of the argument. A domain
error occurs for arguments less than 1. The asinh() and atanh() functions compute the
inverse hyperbolic sine and inverse hyperbolic tangent of the argument respectively.

1 # include < math .h >
double acosh ( double x ) ;
3 double asinh ( double x ) ;
double atanh ( double x ) ;
✆✌
A simple example is

# include < stdio .h >
2 # include < math .h >

4 int main ( void ) {


printf ( " Hyp inverse cosine of 0.5 is : % f \ n " , acosh (0.5) ) ;
6 printf ( " Hyp inverse sine of 0.5 is : % f \ n " , asinh (0.5) ) ;
printf ( " Hyp inverse tangent of 1.5 is : % f \ n " , atanh (1.5) ) ;
8 return 0;
}
✆✌

Hyperbolic inverse cosine at argument 0.5 is : nan
Hyperbolic inverse sine at argument 0.5 is : 0.481212
Hyperbolic inverse tangent at argument 1.5 is : nan
✆✌

1.12.2 Logarithm Function


Exponential & Logarithm
exp() represents the exponential of a value x with base ‘e’. log() represents the logarithm
of a value in natural base ‘e’.

1 # include < math .h >
double exp ( double x ) ;
3 double log ( double x ) ;
✆✌
A simple example is
220 Basic C


1 # include < stdio .h >
# include < math .h >
3

int main ( void ) {


5 printf ( " Exponential of 0.5 is : % f \ n " , exp (0.5) ) ;
printf ( " logarithm of 0.5 at base 10 is : % f \ n " , log (0.5) ) ;
7 return 0;
}
✆✌

Exponential of 0.5 is : 1.648721
logarithm of 0.5 at base 10 is : -0.693147
✆✌

1.12.3 Arithmetic Function


In C, symbol ˆ does not represent to power but presents to XOR bitwise operation. In
‘math.h’ preprocessor provides the power operation via pow () function.

Power
pow () accepts two values. First is base, (b) and second is exponent, (e). Mathematically
this function is equivalent to
Y = be
This function is used as

double pow ( double x , double y ) ;
✆✌
A table consisting cube of first 10 integers ranging from 1 to 10 is shown below. The
formula used is
y = i3
Here, 3 is exponent or power and i is base.

Base Exp Result, y


1 3 1
2 3 8
3 3 27
4 3 64
5 3 125
6 3 216
7 3 343
8 3 512
9 3 729
1.12. MATHEMATIS 221

A simple example is

1 # include < stdio .h >
# include < math .h >
3

int main ( void ) {


5 printf ( " Power of 2 on base 3 is : % f \ n " , pow (3 , 2) ) ;
return 0;
7 }
✆✌

Power of 2 on base 3 is : 9.000000
✆✌

Square Root
sqrt () returns the square root of a given value. Mathematically it is represented as

y= i

Where, i is any number. The syntax of this function is given below:



1 double sqrt ( double x ) ;
✆✌
A table consisting square root of few specific numbers is given below. The formula used
is √
y= i

Integer Squre Root, y


1 1.00
2 1.41
3 1.73
4 2.00
5 2.24
6 2.45
7 2.65
8 2.83
9 3.00

A simple example is

1 # include < stdio .h >
# include < math .h >
3
222 Basic C

int main ( void ) {


5 printf ( " Square root of 1.45 is : % f \ n " , sqrt (1.45) ) ;
return 0;
7 }
✆✌

Square root of 1.45 is : 1.204159
✆✌

Floor
floor () function accepts a real number. Result of floor value of a real number is, either
perfect integer positive or negative as the case may be which is either equal to or less
than the given number. Its syntax is given by

1 double floor ( double x ) ;
✆✌

floor(−1.5) floor(1.5)

−1.5 1.5
bc b bc b

-3 -2 -1 0 1 2 3

A table consisting few positive and negative numbers with their corresponding floor value,
is given below.

Real Number floor(r)


-2.25 -3.00
-2.75 -3.00
-3.00 -3.00
2.25 2.00
2.75 2.00
3.00 3.00

A simple example is

1 # include < stdio .h >
# include < math .h >
3

int main ( void ) {


5 printf ( " Floor of 1.45 is : % f \ n " , floor (1.45) ) ;
printf ( " Floor of -1.45 is : % f \ n " , floor ( -1.45) ) ;
7 return 0;
}
✆✌
1.12. MATHEMATIS 223


Floor of 1.45 is : 1.000000
Floor of -1.45 is : -2.000000
✆✌

Ceiling
ceil () function accepts a real number. Result of ceiling value of a real number is the
perfect integer, either positive or negative as the case may be, which is either equal to or
greater than the given number.

double ceil ( double x ) ;
✆✌

floor(−1.5)
ceil(−1.5)
−1.5
bc b bc

-3 -2 -1 0 1 2 3

floor(1.5)
ceil(1.5)
1.5
bc b bc

-3 -2 -1 0 1 2 3

A table consisting few positive and negative numbers with their corresponding ceiling
value, is given below.

Real Number ceil(r)


-2.25 -2.00
-2.75 -2.00
-3.00 -3.00
2.25 3.00
2.75 3.00
3.00 3.00

A simple example is

1 # include < stdio .h >
# include < math .h >
3

int main ( void ) {


5 printf ( " Ceil of 1.4855 is : % f \ n " , ceil (1.4855) ) ;
printf ( " Ceil of -1.4855 is : % f \ n " , ceil ( -1.4855) ) ;
7 return 0;
}
✆✌
224 Basic C


Ceil of 1.4855 is : 2.000000
Ceil of -1.4855 is : -1.000000
✆✌

Rounds Off
round () function rounds off a fraction number to its nearest perfect integer. The fractional
part about which number is rounded-off is 0.5. This definition is advanced with following
rules.
1. If non-significant digit is less than 5 and is to be rounded off, the previous digit
does not change and non-significant digit is simply dropped. For example 2.301
is significant upto the second place of the decimal then digit 1 is simply dropped
and number is rounded off to 2.30. Similarly 2.304 is rounded off upto two place of
decimal as 2.30.
2. If non-significant digit is greater than 5 and is to be rounded off, the previous digit
(left side digit) is raised by 1 and non-significant digit is dropped. For example 2.306
is significant upto the second place of the decimal then digit 6 is simply dropped
and previous digit (left side digit) 0 is raised by 1 and number is rounded off to
2.31.
3. If the rounding off digit is greater than 5, rounding off digit is simply dropped when
the previous digit (left side digit) is even. For example, when 2.3546 is rounded off,
result is 2.354.

4. If the rounding off digit is greater than 5, rounding off digit is dropped and previous
digit (left side digit) is raised by 1 when the previous digit (left side digit) is odd.
For example, when 2.3576 is rounded off, result is 2.358.
5. In mathematics and specially in pure science, the large numbers are mostly written
in scientific notation form. Hence these numbers are rounded-off upto significant
digits. To round-off a large number upto n digits, the rounding-off process is always
started from leftmost non-zero digit. For example start process from 2 in 2500 and
from 3 in 0.0325.
6. Keep n significant digits and replace rest of digits with zeros.
7. Write number in scientific notation, i.e. a × 10±b form, where a and b are real and
significant numbers.
8. Round off mantissa upto the last significant digit. For example 0.2336 can be written
as 2.336 × 10−1 in scientific notation and if there are only three significant digits
then third significant digit becomes 4 and number becomes 2.34 × 10−1 . Rest of
digits are dropped.
The syntax of this function is given below:

double round ( double x ) ;
✆✌
1.12. MATHEMATIS 225

round () function in math library of C is loosely based on the basic rule of round-off.
Hence in each case, if rounding-off digit is equal to or larger than 5, then previous digit
is raised by 1. A simple example is

1 # include < stdio .h >
# include < math .h >
3

int main ( void ) {


5 printf ( " Rounding of 1.4 is : % f \ n " , round (1.4) ) ;
printf ( " Rounding of 1.6 is : % f \ n " , round (1.6) ) ;
7 return 0;
}
✆✌

Rounding of 1.4 is : 1.000000
Rounding of 1.6 is : 2.000000
✆✌

round(1.6)
round(1.4)
1.4
bc b b bc

1.6
0 1 2 3

Round off negative numbers in C program is given below:



# include < stdio .h >
2 # include < math .h >

4 int main ( void ) {


printf ( " Rounding of -1.4 is : % f \ n " , round ( -1.4) ) ;
6 printf ( " Rounding of -1.6 is : % f \ n " , round ( -1.6) ) ;
return 0;
8 }
✆✌

Rounding of -1.4 is : -1.000000
Rounding of -1.6 is : -2.000000
✆✌

round(−1.6)
round(−1.4)
−1.4
bc b b bc

−1.6
-3 -2 -1 0

Rounding off a number cause rounding off errors. For example a real number 2.56889 is
actual real number is which is rounded off upto 4th decimal place. It becomes 2.5689.
Now the difference of the two values is 2.56889 − 2.5689 = −0.00001. It is error arises
due to rounding off a real number.
226 Basic C

1.12.4 Float Point Arithmetic


A float or a double has three components, (i) a sign bit, (ii) exponent and (iii) mantissa.
A floating point number is written as

f = ±m × b±e

Here, m is mantissa of the number, b is base, i.e. 2 in IEEE-754 standards. e is exponent


of the floating point number. In this section we shall use single point (float ) floating
numbers. A float data type number is 32 bits long and has three components, (i) a sign
bit (first bit from left side), (ii) an exponent (next 8 bits from left side) and (iii) a mantissa
(rest of 23 bits). The exponent is an excess-127 binary notation. This binary number
is also known as exponent bias.

Binary Equivalent Desired Exponent


··· ···
01111100 -3
01111101 -2
01111110 -1
01111111 0
10000000 1
10000001 2
10000010 3
··· ···

In this notation, binary number 01111111, equivalent to decimal 127 is a binary ex-
ponent equivalent to decimal 0. The next binary exponent i.e. sum of binary 01111111
and bit 1 represents to exponent equivalent to decimal 1 (equivalent to binary 10000000).
Similarly, subtraction of bit 1 from 01111111 represents to exponent equivalent to deci-
mal −1 (equivalent to binary 01111110). Remember that for binary equivalent form of
floating point numbers, base is 2, i.e. exponent binary 01111111 is equal to in decimal
form of 20 , exponent binary 10000000 means 21 , exponent binary 01111110 means 2−1
and so on.

125 126 127 128 129 Decimals

01111101 01111110 01111111 10000000 10000001 Excess-127

e-Line
−2 −1 0 1 2

2−2 2−1 20 21 22 2e Value


1.12. MATHEMATIS 227

The decimal exponent equivalent to binary exponent is obtained by subtracting 01111111


from the given binary exponent. The mantissa binary numbers are solved from left side
to right side. Here, we are dealing with binary fractions, so the leftmost mantissa bit
means 2−1 , the next right bit has meaning of 2−2 and so on. The place values of mantissa
bits from left side to right side are 2−1 , 2−2 , 2−3 etc. The first bit of a non-zero binary
significant is always 1. Hence mantissa in fractions is given by
n
X
M =1+ biti × 2−i
i=1

Here, i is ith bit counted from left hand side to right hand side in mantissa part. n is
total number of significant digits in mantissa.
Illustrated Example Assume a floating point representation ‘0 0111 1100 0000 0000
0000 0000 0000 000’ shown in binary form. The sign bit of this binary number is ‘0’,
hence it is positive value. The exponent binary number is 01111100 and mantissa number
is 0000 0000 0000 0000 0000 000. Note that if left most digit of the binary exponent part
of floating point number is ‘0’, then exponent is obtained by subtracting 01111111 from
the given binary exponent. Here, binary subtraction of

01111100
-01111111
-00000011

which is equivalent to decimal −3. The exponent value is −3. The mantissa part is
all zero, hence
X23
M =1+ biti × 2−i
i=1

gives mantissa ‘1’. Now, the number is

r = 1 × 2−3

It gives 0.125.
Illustrated Example Assume a floating point representation ‘0 1010 0110 1101 0001
1010 1001 0100 101’ shown in binary form. The sign bit of this binary number is ‘0’,
hence it is positive value. The exponent binary number is 10100110 and mantissa number
is 1101 0001 1010 1001 0100 101. Note that, if the left most digit is of binary exponent is
‘1’, then exponent is obtained by subtracting 01111111 from the given binary exponent.
Here, binary subtraction of

10100110
-01111111
00100111
228 Basic C

which is equivalent to decimal 39. The exponent value is 39. The mantissa part is
23
X
M =1+ bitn × 2−n
n

gives mantissa ‘1.818989396095270’. Now, the number is

r = 1.818989396095270 × 239

It gives 999999995904. Numerical programming languages use double type floating point
mathematics. Therefore each number is denoted as float point, i.e. 1.0 as 1.000000, 0.5 as
0.500000. Sometime, even zero is represented as 2.5 × 10−18 or as 13.2 × 10−19 etc. where
these values are very very small and are close to zero. Here zero is taken as comparative
value rather than absolute value. For example, sometimes, in numerical calculations,
identity matrix is represented as

1 3.5 × 10−12






35 × 10−12 1

Operators in Float Points Arithmetic


Normally, all the arithmetic operators may be used in floating point arithmetic. In float
point arithmetic, mixing of two different floating points are allowed. A float or double
data type value can be used with int data type value. The result of mixed data type
values is extended to match the precision of the more precise data type value. Floating
point division does not discard the fractional part and produce round off errors.

# include < stdio .h >
2

int main ( void ) {


4 printf ( " 2 + 2.0 is %f\n", 2 + 2.0) ;
printf ( " 2 - 2.0 is %f\n", 2 - 2.0) ;
6 printf ( " 2 / 2.0 is %f\n", 2 / 2.0) ;
printf ( " 2 * 2.0 is %f\n", 2 * 2.0) ;
8 return 0;
}
✆✌

2 + 2.0 is 4.000000
2 - 2.0 is 0.000000
2 / 2.0 is 1.000000
2 * 2.0 is 4.000000
✆✌
Few operators do not work with floating-point datatypes., i.e. real numbers. These are
% (modulo) and all of the bitwise operators, like ∼, <<, >>, &, ˆ, and |.

# include < stdio .h >
2

int main ( void ) {


1.12. MATHEMATIS 229

4 /* Will show errors */


printf ( " 2 % 2.0 is % f \ n " , 2 % 2.0) ;
6 /* Will show errors */
printf ( " 2 ^ 2.0 is % f \ n " , 2 ^ 2.0) ;
8 return 0;
}
✆✌
An int data type value can be converted into floating point type by casting it.

1 # include < stdio .h >

3 int main ( void ) {


printf ( " 2 is % f \ n " , ( float ) 2) ;
5 printf ( " 2 is % lf \ n " , ( double ) 2) ;
return 0;
7 }
✆✌

2 is 2.000000
2 is 2.000000
✆✌
Few of the floating values are shown in the following table.

Float Decimal Binary Form


0 0 0 00000000 00000000000000000000000
-0 -0 1 00000000 00000000000000000000000
0.1 0.10000000149011612 0 01111011 10011001100110011001101
0.125 0.125 0 01111100 00000000000000000000000
0.25 0.25 0 01111101 00000000000000000000000
1 1 0 01111111 00000000000000000000000
2 2 0 10000000 00000000000000000000000
1e+12 999999995904 0 10100110 11010001101010010100101
inf inf 0 11111111 00000000000000000000000
-inf -inf 1 11111111 00000000000000000000000
nan nan 0 11111111 10000000000000000000000

A value is said to be positive infinity (0×7f 800000) when its sign bit is 0 and exponent
is 0×f f and all mantissa bits are 0. Similarly, a value is said to be negative infinity
(0×f f 800000) when its sign bit is 1 and exponent is 0×f f and all mantissa bits are 0.
A not-a-number (0×7f c00000) case arises when sign bit of floating point number is 0,
exponent is 0×f f and mantissa is 0×400000.
230 Basic C

Astray Result
Sometimes when a float data type number is printed in output console, it gives strange
result. Like 3.1 prints as 3.0999999. Its reason is that most hardware uses base 2 for
floating-point numbers rather than base 10. All the fractions in base 10 (decimal form) can
not be represented in base 2 (binary form). This is why, decimal fraction 3.1 sometimes
printed as 3.0999999.

Double Floating Point


A double is 64 bits long and has three components, (i) a sign bit (first bit from left side),
(ii) exponent (next 11 bits from left side) and (iii) mantissa (rest of 52 bits). A double
point floating point number is written as
f = ±m × b±e
Here, m is mantissa of the number, b is base either ‘10’ or ‘e’ or ‘2’ and n is exponent
of the floating type number. In computers, the base is ‘2’. Binary number 1111111111
equivalent to decimal 1023 is used as Exponent bias.

1.12.5 Zero Crossing


A function is said to be zero-crossing function if its sign changes when its independent
variable crosses to zero in a number line. For example
f (x) = x; for − 1 < x < 1
changes its sign when x crosses to zero. Similarly
f (x) = sin(x); for − 4 < x < 4
is also a zero crossing function which changes its sign when x crosses to zero. Zero crossing
has emmence importance in electrical and computer science.

Limit At Zero
In mathematics, limit is a finite value of a continuous function at a given point. It is
represented as
lim f (x) = k
x→a
Where k is fininte value of the function at given point ‘a’. If ‘a’ is zero then some functions
behave strangly and do not give finite value, i.e. converging value at the point of limit.
Assume a function, here y = sin(x), which converges to a finite value at point ‘0’
lim y = lim sin(x) = 0
x→0 x→0

b
x
(0, 0)
1.12. MATHEMATIS 231

Contrast to these types of functions, fraction functions diverge to ∞ when x → 0. See


the following limit equation for function y = 1/x,
1
lim y = lim =∞
x→0 x→0 x

Now, it is not possible to use this function with other functions in mathematical op-
erations. To avoid it, we take approaching limit to point ‘0’ of the function as given
below:
1
lim y = lim = ∞; when [−∞, 0) < x < (0, ∞]
x→0 x→0 x

b
x
(0, 0)

Here, ±∞ is acceptable as 1/ ± ∞ = 0, which is a finite value.

1.12.6 Random Number Generator


Following C program is used to generate random numbers. A user defined seed control
the initial random number and subsequent random numbers are used as seed for next
random number. This program given first five random number against a seed value.

# include < stdio .h >
2 extern void SeedToNew ( unsigned int x ) ;
extern int MyRand ( void ) ;
4

int main ( void ) {


6 int count ;
unsigned seed ;
8 printf ( " Please enter seed .\ n " ) ;
while ( scanf ( " % u " , & seed ) == 1) {
10 SeedToNew ( seed ) ;
for ( count = 0; count < 5; count ++)
12 printf ( " % hd \ n " , MyRand () ) ;
printf ( " Please enter newSeed ( q to quit ) :\ n " ) ;
14 }
printf ( " Done \ n " ) ;
16 return 0;
}
18
232 Array & Pointer

static unsigned long int newSeed = 1; /* the seed */


20

int MyRand ( void ) {


22 newSeed = newSeed * 1103515245 + 12345;
return ( unsigned int ) ( newSeed / 65536) % 32768;
24 }

26 void SeedToNew ( unsigned int seed ) {


newSeed = seed ;
28 }
✆✌
In the codes in line

return ( unsigned int ) ( newSeed / 65536) % 32768;
✆✌
The value 32768 is used to control the limits of the random number. If it is 10 then all
the random number will be within 0 to 10.
2.1. ARRAY 233

2 Array & Pointer

2.1 Array
Arrays in C stores data in a single variable name with an index, also known as a subscript.
It is simply a list or ordered grouping for variables of the same type. Arrays often help a
programmer in organize collections of data efficiently and intuitively. A character array
takes one byte for each character while an integer array takes 4 bytes for one integer.
Other datatypes takes appropriate bytes to stores that data type value.

myStrA

A B C D E F ‘\0’

Figure 2.1: Array of first six alphabetic characters stored in memory and pointed by
variable ‘myStrA’.

myNumA myN umA[0] myN umA[1]

00000001 00000010

Figure 2.2: Array of two integers pointed by variable ‘myNumA’ are stored in memory
as shown this figure. Each integer needs four bytes memory space.

2.1.1 Uni-Dimensional Array


Arrays are declared by two ways, (i) static and (ii) dynamic. Static arrays are declared
using square brackets containing size of array. Dynamic arrays are declared with pointers.
In static declaration, compiler creates space required for storing of data at declaration
and then returns the address of memory space created. In case of string, one extra
space for null terminator is also reserved. In case of dynamic declaration only address
of proposed memory space is returned where proposed data may be stored. It does not
reserve memory space. To create memory space, function malloc is used. Note that only
string arrays have terminating marker (\0). Other type of arrays must be controlled by
array size. muArrays are declared and initialized like

1 int numbers [6]; // array declared & space created
int point [6]={0 ,0 ,1 ,0 ,0 ,0}; // array declared , space
3 // created and initialized
✆✌
234 Array & Pointer

Remember that the initialization of static array is take place alongwith its declaration.
Otherwise initialization of an array shows compile time error.

1 char myS [];
myS = " My String " ; /* Illegal initializati on . */
3 // Actually , above action was copying of data to
// array , not initialisati on . Copying of data done
5 // by copying character one by one in memory space
char myStr []= " My String " ; /* Legal initializat io n . */
✆✌
Initialisation of array with pointer after declaration is compiler dependent.

# include < stdio .h >
2

int main () {
4 char * c = " This " ;
c = " That " ;
6 printf ( " % s " , c ) ;
return 0;
8 }
✆✌

That
✆✌
The brackets ([ ]) identify ‘numbers’ or ‘points’ and the number enclosed in the brackets
indicates the number of elements in the array. An element of the array can be accessed by
its index number i.e. subscripts of the array. When square bracket symbol in static array
declaration does not contain size of array then it is called dynamic declaration of array.
Dynamic array declaration is permitted if it is initialised at the time of declaration. In
following example, each element of the array is accessed by its index number.

1 # include < stdio .h >

3 int main ( void ) {


int ix ;
5 short anArray [ ] = {3 , 6 , 9 , 12 , 15};
for ( ix = 0; ix < ( sizeof ( anArray ) / sizeof ( short ) ) ; ++ ix ) {
7 printf ( " The array value is % d .\ n " , anArray [ ix ]) ;
}
9 }
✆✌

anArray

3 6 9 12 15
i0 i1 i2 i3 i4

Figure 2.3: Head integer value consumes 4 byte memory space. in represents to the index
of elements of array ‘days’. Total bytes of memory used to store data is 5 × 4 = 20.
2.1. ARRAY 235

In the above example, the size of the array was not explicitly specified. The compiler
knows the size of array from the initialized list. The size of ‘anArray’ is ‘5’ because
‘anArray’ has five elements. Addition of an additional element to the list will increase its
size to six. Static declaration of the size of an array, the array list will be overflow. To
overcome this problem sizeof expression is used as

1 size = sizeof ( anArray ) / sizeof ( short )
✆✌
As the sizeof expression in the for loop, the script is automatically adjusted to this
change. Designated initializer is allow to pick and choose the initialized elements. If the
last element of an array is initialized then in the initialization syntax of traditional C,
there is a requirement of initialization of every element preceding to the last one. An
array, if initialized, then each element value is index from 0 to n − 1, where n is size of
the array. For example,

1 int count [] = {31 , 28 , 30 , 29 , 32 , 27}; // array size is 6
✆✌
has six elements. The element value at index 0 is 31, element value at index 1 is 28 and
so on. The index of array element may be redefined inside the array as the method given
in following syntax

1 /* int count [] = {[ < new index >]= < array element value >}; */
int count [] = {31 , [2] = 28 , 30 , 29 , 32 , 27};
✆✌
Here, the index of second element is 2, i.e. element shall be stored at third place of
memory of integer data type. Elements of an array are overridable, i.e. new element
value at index 4 can be override the old value of the element at the index 4 if any other
element is assigned the index value 4.

# include < stdio .h >
2 # define MONTHS 12

4 int main ( void ) {


int days [ MONTHS ] = {31 , 28 , [4] = 31 , 30 , 31 , [1] = 29};
6 int i ;
for ( i = 0; i < MONTHS ; i ++)
8 printf ( " %2 d % d \ n " , i + 1 , days [ i ]) ;
return 0;
10 }
✆✌
In above program example, array ‘days’ has first element (at index position 0) 31, second
element (at index position 1) is 28. Next element, 30, of the array ‘days’ is declared for
index 4, i.e. for 5th position. Next element is 30 in the array ‘days’. Its position shall
be next to the previous element, i.e. after 5th position, therefore this element will be at
6th position or at index position 5. Element for index position 6 is 31. Last element is
defined for index position 1. Hence previous element, 28, which was at the index position
1 shall be replaced by value 29. The final arrangement of the array data in the memory
shall be as shown in the below figure.
236 Array & Pointer

days

31 29 0 0 31 30 31 0 0 0 0 0
i0 i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11

Figure 2.4: Arrangement of elements of array ‘days’ in memory. Here, each block rep-
resents to an integer data byte (i.e. group of four memory bytes). in represents to the
index of elements of array ‘days’.


1 31
2 29
3 0
4 0
5 31
6 30
7 31
8 0
9 0
10 0
11 0
12 0
✆✌
An array initialised with ‘[ ]’ is called expandable array. When an array is declared
without its size, compiler first count the array elements and then it grows the array upto
a size so that all the elements can stored in the array.

/* Array with growing size . */
2 int days [ ] = {31 , 28 , [4] = 31 , 30 , 31 , [1] = 29};
✆✌

# include < stdio .h >
2

int main ( void ) {


4 int days [] = {31 , 28 , [4] = 31 , 30 , 31 , [1] = 29};
int i ;
6 printf ( " Size of array is % d \ n " , sizeof ( days ) / sizeof ( int )) ;
/* Here sizeof ( days ) / sizeof ( int ) is not *
8 * grouped as ‘/ ’ higher precedence to ‘<’ */
for ( i = 0; i < sizeof ( days ) / sizeof ( int ) ; i ++)
10 printf ( " %2 d % d \ n " , i , days [ i ]) ;
return 0;
12 }
✆✌

Size of array is 7
0 31
1 29
2 0
3 0
4 31
5 30
2.1. ARRAY 237

6 31
✆✌

2.1.2 Multi-Dimensional Array


An array declaration in C is given by

int myA [ m ][ n ]; /* m rows and n cols . */
✆✌
If the size of integer type array is fixed as shown above, compiler reserves m × n × k bytes
memory. Here, k is size of variable data type. For integer it is 4 as integer is 4 bytes long
data type. Hence, memory size allocated for integer array of type m × n is 4mn. Assume
a 2 × 2 integer array as shown below

1 int myA [2][2] = {
{10 , 20} ,
3 {15 , 2}
};
✆✌
The memory allocated for this array is 2 × 2 × 4 = 16 bytes. As column size of this array
is 2, hence 8 bytes are taken in a group for two columns, in which each column uses 4
bytes for storing integer data. Remember that, in following figures, each cell represents
to one byte. This is why, an integer is represented here as a group of four bytes. It is
done, for convenient to calculate the number of bytes required to store an array data.
And in computer, the index counting is started from ‘0’ instead of ‘1’.

myA c0 c1
r0 10 0 0 0 20 0 0 0

r1 15 0 0 0 2 0 0 0

In above figure, the byte position of array data is shown into two rows and two column.
Practically above data is stored in memory as continuous data bytes.

myA 1st col 2nd col 1st col 2nd col

10 0 0 0 20 0 0 0 15 0 0 0 2 0 0 0

1st row 2nd row

From the above arrangement of data, in a multi-dimensional array, number of rows


may be constant or variable but number of columns must be constant. The reason is
that, elements of an array are arranged one by one sequentially, so if column size is not
fixed then pointer-to-array variable will not be able to identify the starting of next row
of the array. See the example below:
238 Array & Pointer


# include < stdio .h >
2

int main () {
4 int i ;
int myA [2][2] = { /* 2 X2X4 =16 bytes */
6 {10 , 20} ,
{15 , 2}
8 };
printf ( " Size of array is % d \ n " , sizeof ( myA ) ) ;
10 char * p = ( char *) & myA ; // Cast int into char ptr
for ( i = 0; i < sizeof ( myA ) ; i ++) {
12 printf ( " % d " , p [ i ]) ; // print all 16 bytes
}
14 return 0;
}
✆✌

Size of array is 16
10 0 0 0 20 0 0 0 15 0 0 0 2 0 0 0
✆✌
Now, an array having two columns but dynamic rows is declared and assigned as the
syntax is given below:

int myB [ ][2] = {
2 {10 , 20} ,
{15 , 2} ,
4 {1 , 4}
};
✆✌
The memory allocated for this array is dynamic. This array has two columns hence
memory is allocated in the multiple of 2 × 4 = 8 bytes. If there are two rows then
memory allocation will be expanded to 8 × 2 = 16 bytes. Similarly if there are three
rows then memory allocation will be expanded to 8 × 3 = 24 bytes and so on, subject to
memory sharing is not violated.

myA c0 c1
r0 10 0 0 0 20 0 0 0

r1 15 0 0 0 2 0 0 0

r2 1 0 0 0 4 0 0 0

See the example below:



1 # include < stdio .h >
2.1. ARRAY 239

3 int main () {
int i ;
5 /* Array has fixed cols & dynamic rows */
int myB [ ][2] = {
7 {10 , 20} ,
{15 , 2} ,
9 {1 , 4}
};
11 printf ( " Size of array is % d \ n " , sizeof ( myB ) ) ;
char * p = ( char *) & myB ;
13 for ( i = 0; i < sizeof ( myB ) ; i ++) {
printf ( " % d " , p [ i ]) ;
15 }
return 0;
17 }
✆✌

Size of array is 24
10 0 0 0 20 0 0 0 15 0 0 0 2 0 0 0 1 0 0 0 4 0 0 0
✆✌
An array having two rows and three columns is declared and initialized as shown in the
syntax given below:

int two_d [2][3] = {{ 5 , 2 , 1 } ,
2 { 6 , 7 , 8 }};
✆✌
Where [2] represents to the number of rows and [3] represents to the number of columns of
the two dimensional array. A three dimensional array is declared as given in the following
syntax:

int myA [ ][3][2];
2 /* | | | *
* l r c */
✆✌
This array has two columns (y-axis represented as ‘c’ here), three rows (x-axis represented
as ‘r’ here) and variable number of layers (z-axis represented as ‘l’ here). In C programs,
which contains three dimensional array, the z-axis (i.e. third dimension) is always outer-
most loop. Practically, three dimensional array is layers of two dimensional arrays. As
shown in the following figure, a 3 × 2 array is placed in four layers and collectively, they
form a 3 × 2 × 4 three dimensional array.
240 Array & Pointer
l0
c0 c1
l1
r0 0 0 0 0 0 0 0 0
c0 c1
l2
r1 0 0 0 r00 0 0 0 0 0 0 0 0
c0 c1
l3
r2 0 0 0 r01 0 0 0 r00 0 0 0 0 0 0 0 0
c0 c1
r2 0 0 0 r01 0 0 0 r00 0 0 0 0 0 0 0 0

r2 0 0 0 r01 0 0 0 0 0 0 0 0

r2 0 0 0 0 0 0 0 0

A three dimensional array is arranged in patterns as shown in below figure.


l0 l1
myA c0 c1 c0 c1
r0 0 0 0 0 0 0 0 0 r0 0 0 0 0 0 0 0 0

r1 0 0 0 0 0 0 0 0 r1 0 0 0 0 0 0 0 0

r2 0 0 0 0 0 0 0 0 r2 0 0 0 0 0 0 0 0

The memory arrangement of three dimensional array is given in the following figure.

myA c0 of r0 c1 of r0 c0 of r1 c1 of r1

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

r0 of l0 r1 of l0

Multi-dimensional array can be used to add, subtract and product (either dot or cross)
of two vectors or matrices. Following is an example using an array of 5 × 5 dimension.
This example requires 5 × 5 × 4 = 100 bytes.

1 # include < stdio .h >
# define X 5
3 # define Y 5

5 int main ( void ) {


int ix , iy ;
7

short anArray [ X ][ Y ]; /* 100 bytes memory requirement . */


9 for ( ix = 0; ix < X ; ++ ix ) {
for ( iy = 0; iy < Y ; ++ iy ) {
2.1. ARRAY 241

11 anArray [ ix ][ iy ] = ix * iy ;
};
13 }
for ( ix = 0; ix < X ; ++ ix ) {
15 for ( iy = 0; iy < Y ; ++ iy ) {
printf ( " %2 d \ t " , anArray [ ix ][ iy ]) ;
17 };
printf ( " \ n " ) ;
19 }
}
✆✌

0 0 0 0 0
0 1 2 3 4
0 2 4 6 8
0 3 6 9 12
0 4 8 12 16
✆✌
Multidimentional array can be extended in matrix manipulations, additions, subtractions,
multiplications and divisions. In the following example, two matrices are added and
subtracted element-wise. The element-wise addition and subtraction is given by

Cij = Aij ± Bij



1 # include < stdio .h >

3 /* Random number generator between 0 to 10. */


int rand_num ( int a , int b ) {
5 return (( a * 97 + b *21) & 10) ;
}
7

int main () {
9 int i /* row */ ,
j /* col */ ;
11 int A [3][3] /* First Matrix */ ,
B [3][3] /* Second Matrix */ ,
13 C [3][3] /* Third Matrix */ ;
printf ( " First Random Matrix is :\ n " ) ;
15 /* For each of three rows */
for ( i = 0; i < 3; i ++) {
17 /* There are three columns . */
for ( j = 0; j < 3; j ++) {
19 /* Assign a random matrix elements . */
A [ i ][ j ] = rand_num ( i *j , j ) ;
21 printf ( " %3 d \ t " , A [ i ][ j ]) ;
}
23 /* Print new line after completion of each row */
printf ( " \ n \ n " ) ;
25 }
printf ( " \ nSecond Random Matrix is :\ n " ) ;
27 /* For each of three rows */
242 Array & Pointer

for ( i = 0; i < 3; i ++) {


29 /* There are three columns . */
for ( j = 0; j < 3; j ++) {
31 /* Assign a random matrix elements . */
B [ i ][ j ] = rand_num (i , i * j ) ;
33 printf ( " %3 d \ t " , B [ i ][ j ]) ;
}
35 /* Print new line after completion of each row */
printf ( " \ n \ n " ) ;
37 }
printf ( " \ nElementwise Addition of Matrix is :\ n " ) ;
39 /* For each of three rows */
for ( i = 0; i < 3; i ++) {
41 /* There are three columns . */
for ( j = 0; j < 3; j ++) {
43 /* Add matrices elementwise . */
C [ i ][ j ] = A [ i ][ j ] + B [ i ][ j ];
45 printf ( " %3 d \ t " , C [ i ][ j ]) ;
}
47 /* Print new line after completion of each row */
printf ( " \ n \ n " ) ;
49 }
printf ( " \ nElementwise Subtraction of Matrix is :\ n " ) ;
51 /* For each of three rows */
for ( i = 0; i < 3; i ++) {
53 /* There are three columns . */
for ( j = 0; j < 3; j ++) {
55 /* Subtract matrices elementwise . */
C [ i ][ j ] = A [ i ][ j ] - B [ i ][ j ];
57 printf ( " %3 d \ t " , C [ i ][ j ]) ;
}
59 /* Print new line after completion of each row */
printf ( " \ n \ n " ) ;
61 }
return 0;
63 }
✆✌

First Random Matrix is :
0 0 10
0 2 8
0 2 10
Second Random Matrix is :
0 0 0
0 2 10
2 8 2
Elementwise Addition of Matrix is :
0 0 10
0 4 18
2 10 12
Elementwise Subtraction of Matrix is :
0 0 10
2.1. ARRAY 243

0 0 -2
-2 -6 8
✆✌
The vector and scalar products between two matrices can also be done. The dot product
of two matrices is given by
Cij = A~ ij · B
~ ij
In the following example, dot products between to matrices is performed.

# include < stdio .h >
2

/* Random number generator between 0 to 10. */


4 int rand_num ( int a ) {
return (( a * 1011457789 + 12345) & 10) ;
6 }

8 int main () {
int i /* row */ ,
10 j /* col */ ;
int A [3][3] /* First Matrix */ ,
12 B [3][3] /* Second Matrix */ ,
C [3][3] /* Dot Matrix */ ;
14 printf ( " First Random Matrix is :\ n " ) ;
/* For each of three rows */
16 for ( i = 0; i < 3; i ++) {
/* There are three columns . */
18 for ( j = 0; j < 3; j ++) {
/* Assign a random matrix elements . */
20 A [ i ][ j ] = rand_num ( i + j ) ;
printf ( " % d \ t " , A [ i ][ j ]) ;
22 }
/* Print new line after completion of each row */
24 printf ( " \ n \ n " ) ;
}
26 printf ( " \ nSecond Random Matrix is :\ n " ) ;
/* For each of three rows */
28 for ( i = 0; i < 3; i ++) {
/* There are three columns . */
30 for ( j = 0; j < 3; j ++) {
/* Assign a random matrix elements . */
32 B [ i ][ j ] = rand_num ( i * j ) ;
printf ( " % d \ t " , B [ i ][ j ]) ;
34 }
/* Print new line after completion of each row */
36 printf ( " \ n \ n " ) ;
}
38 printf ( " \ nDot Product Matrix is :\ n " ) ;
/* For each of three rows */
40 for ( i = 0; i < 3; i ++) {
/* There are three columns . */
42 for ( j = 0; j < 3; j ++) {
/* Elementwise dot product of matrices . */
244 Array & Pointer

44 C [ i ][ j ] = A [ i ][ j ] * B [ i ][ j ];
printf ( " % d \ t " , C [ i ][ j ]) ;
46 }
/* Print new line after completion of each row */
48 printf ( " \ n \ n " ) ;
}
50 return 0;
}
✆✌

First Random Matrix is :
8 2 2
2 2 0
2 0 8
Second Random Matrix is :
8 8 8
8 2 2
8 2 8
Dot Product Matrix is :
64 16 16
16 4 0
16 0 64
✆✌
The cross product (vector product) of two matrices is given by
~ =A
C ~×B
~

# include < stdio .h >
2

/* Random number generator between 0 to 10. */


4 int newseed =10;
int seed ( int a ) {
6 newseed = newseed + a ;
return newseed ;
8 }
int rand_num ( int a ) {
10 seed ( a ) ;
return (( newseed * 99991 + 12345) & 10) ;
12 }

14 int main () {
int i /* row */ ;
16 int A [3] /* First Vector */ ,
B [3] /* Second Vector */ ,
18 C [3] /* Dot Vector */ ;
printf ( " First Random Vector is :\ n " ) ;
20 /* For each of three rows */
for ( i = 0; i < 3; i ++) {
22 /* Assign a random vector elements . */
A [ i ] = rand_num ( i ) ;
24 printf ( " % d \ t " , A [ i ]) ;
2.1. ARRAY 245

}
26 /* Print new line after completion of each row */
printf ( " \ n " ) ;
28

printf ( " \ nSecond Random Vector is :\ n " ) ;


30 /* For each of three rows */
for ( i = 0; i < 3; i ++) {
32 /* Assign a random vector elements . */
B [ i ] = rand_num ( i ) ;
34 printf ( " % d \ t " , B [ i ]) ;
/* Print new line after completion of each row */
36 }
printf ( " \ n " ) ;
38

printf ( " \ nCross Product Vector is :\ n " ) ;


40 /* For each of three rows */
for ( i = 0; i < 3; i ++) {
42 /* Elementwise cross product of matrices . */
C [ i ] = pow ( -1 ,2* i ) * ( A [( i +1) %3] * B [( i +2) %3] \
44 - B [( i +1) %3] * A [( i +2) %3]) ;
printf ( " % d \ t " , C [ i ]) ;
46 }
/* Print new line after completion of each row */
48 printf ( " \ n \ n " ) ;

50 return 0;
}
✆✌

First Random Vector is :
10 2 0
Second Random Vector is :
0 10 8
Cross Product Vector is :
16 -80 100
✆✌
Arrays can be passed to a function as its parameter (argument) as shown in the example
given below:

# include < stdio .h >
2 /* + - Array pointer with **
**| expandable size */
4 void init_array ( int a [ ] , int count ) {
int i ;
6 for ( i = 0; i < count ; i ++)
a [ i ] = i * 10;
8 for ( i = 0; i < count ; i ++)
printf ( " The a value is % d .\ n " , a [ i ]) ;
10 }

12 int main ( void ) {


int mydata [10];
246 Array & Pointer

14 init_array ( mydata , 5) ;
return 0;
16 }
✆✌

The a value is 0.
The a value is 10.
The a value is 20.
The a value is 30.
The a value is 40.
✆✌
For multidimensional array, there is no limit of dimension in C. Here, a four dimensional
matrix is represented by

1 int myData [2][3][2][4]
✆✌
A new dimension in array declaration is always grouped by curly braces. One dimensional
array has one curly braces, i.e. one row. In two dimensional array, there are two one
dimensional rows both separated by comma (,) operator. These two rows are enclosed by
another curly braces. In three dimensional systems of arrays, two 2-dimensional arrays
are placed one over another. In the following example, two, three and four dimensional
arrays are declared.

1 # include < stdio .h >

3 int main () {
char a [2][2] = {
5 // cols
{1 , 2} , // row
7 {5 , 6} // row
};
9 char b [2][2][2] = {
{
11 // cols
{1 , 2} , // row
13 {5 , 6} // row
},
15 { // height
{4 , 3} ,
17 {8 , 9}
}
19 };
char c [2][2][2][2] = {
21 {
{
23 // cols
{1 , 2} , // row
25 {5 , 6} // row
},
27 { // height
{1 , 2} ,
2.1. ARRAY 247

29 {5 , 6}
}
31 },
{ // time
33 {
{4 , 1} ,
35 {7 , 6}
},
37 {
{4 , 4} ,
39 {9 , 1}
}
41 }
};
43 int i , j , k , l ;
printf ( " Elements of matrix a are \ n " ) ;
45 for ( i = 0; i < 2; i ++) {
for ( j = 0; j < 2; j ++) {
47 printf ( " Element a [% d ][% d ] is : % d \ n " ,
i +1 , j +1 , a [ i ][ j ]) ;
49 }
}
51 printf ( " Elements of matrix b are \ n " ) ;
for ( i = 0; i < 2; i ++) {
53 for ( j = 0; j < 2; j ++) {
for ( k = 0; k < 2; k ++) {
55 printf ( " Element b [% d ][% d ][% d ] is : % d \ n " ,
i +1 , j +1 , k +1 , b [ i ][ j ][ k ]) ;
57 }
}
59 }
printf ( " Elements of matrix c are \ n " ) ;
61 for ( i = 0; i < 2; i ++) {
for ( j = 0; j < 2; j ++) {
63 for ( k = 0; k < 2; k ++) {
for ( l = 0; l < 2; l ++) {
65 printf ( " Element c [% d ][% d ][% d ][% d ] is : % d \ n " ,
i +1 , j +1 , k +1 , l +1 , c [ i ][ j ][ k ][ l ]) ;
67 }
}
69 }
}
71 return 0;
}
✆✌
It is an example of the two dimensional matrix in which total and average marks of each
student is calculated.

# include < stdio .h >
2 # define STUDENT 3 // number of STUDENTS
# define SUBJECT 5 // number of SUBJECT
248 Array & Pointer

int main ( void ) {


6 // marks of five stus
const float marks [ STUDENT ][ SUBJECT ] = {
8 // subs ->
{9.9 , 8.0 , 8.3 , 4.2 , 6.0} , // stu row
10 {9.0 , 7.0 , 7.3 , 2.0 , 5.0} , // stu row
{9.6 , 8.0 , 8.8 , 2.1 , 5.5} , // stu row
12 };
int stu , sub ;
14 float subtot , total ;
printf ( " Student Marks ( Max 50) \ n " ) ;
16

/* for each stu , sum marks for each sub */


18 total = 0;
for ( stu = 0; stu < STUDENT ; stu ++) {
20 for ( sub = 0 , subtot = 0; sub < SUBJECT ; sub ++) {
subtot += *(*( marks + stu ) + sub ) ;
22 }
printf ( " % s % d %20.1 f \ n " , " Stu " , stu + 1 , subtot ) ;
24 total += subtot ; /* total for all stus */
}
26 printf ( " \ nThe student average is %.1 f .\ n \ n " ,
total / STUDENT ) ;
28

printf ( " Subject Average :\ n " ) ;


30 printf ( " Sub_1 Sub_2 Sub_3 Sub_4 Sub_5 \ n " ) ;

32 /* for each sub , sum marks over stus */


for ( sub = 0; sub < SUBJECT ; sub ++) {
34 subtot = 0;
for ( stu = 0; stu < STUDENT ; stu ++) {
36 subtot += *(*( marks + stu ) + sub ) ;
}
38 printf ( " %5.1 f " , subtot / STUDENT ) ;
}
40 printf ( " \ n " ) ;
return 0;
42 }
✆✌

Student Marks ( Max 50)
Stu 1 36.4
Stu 2 30.3
Stu 3 34.0

The student average is 33.6.

Subject Average :
Sub _1 Sub _2 Sub _3 Sub _4 Sub _5
9.5 7.7 8.1 2.8 5.5
✆✌
2.1. ARRAY 249

A multidimensional array may also be returned by a function, if function is used as a


pointer. An example for two dimensional array as a returned value of a function is given
below:

# include < stdio .h >
2

int (* myF ( int arr [3][3] , int n ) ) [3] {


4 int i , j ;
for ( i = 0; i < 3; i ++) {
6 for ( j = 0; j < 3; j ++) {
arr [ i ][ j ] = i + j ;
8 }
}
10 return arr ;
}
12

int main () {
14 int arr [3][3];
int (* q ) [3] = myF ( arr , 3) ;
16 int i , j ;
for ( i = 0; i < 3; i ++) {
18 for ( j = 0; j < 3; j ++) {
printf ( " % d " , q [ i ][ j ]) ;
20 }
printf ( " \ n " ) ;
22 }
}
✆✌

0 1 2
1 2 3
2 3 4
✆✌

2.1.3 Array of Strings


It is very simple to declara an array for integers, float, characters datatypes as they has
fixed size. But, in case of string, declaration of array is complex as size of string, being
stored in array like matrix form, is variable. For example, at a particular cell, we can store
string “me” or string “our”. Here, both words have different size. So, declaration of an
array for string needs special caution and care. Here, we shall discuss about the storing of
string data in an array, starting from one dimensional array to multi-dimensional array.
Suppose we have to store string “This”. We declare array like

1 char myArr [];
✆✌
Here, ‘[]’ controls the size of declared variable ‘myArr’ as dynamic and memory is allocated
and reallocated by compiler at run time according to the size of input string being stored.
Now, we store string “This” in this array, and appended by null terminator. The memory
data shall be looked like-
250 Array & Pointer

myArr

T h i s \0
0×0012 0×0013 0×0014 0×0015 0×0016 0×0017 0×0018 0×0019

Figure 2.5:

But what happens if we declare an fixed size one dimensional array as shown below:

1 char myArr [10];
✆✌
It means, above array may store only 10 characters including null terminator.

1 # include < stdio .h >
# include < string .h >
3

int main () {
5 char myArr []= " This " ;
printf ( " String is ’% s ’\ n " , myArr ) ;
7 return 0;
}
✆✌

String is ’ This ’
✆✌
If we try to store string of size more than 10 characters, data shall be overflow. From
figure 2.5, it is seen that each character of string ‘This’ is column of one row vector.
Therefore, when we declare a two dimensional array, one new parameter is required for
rows of the array alongwith other size of string parameter.

1 char myArr [ < rows >][ < string size in each row >]
✆✌
For example, an array

1 char myArr [3][5]
✆✌
tells us that, there are three rows and each row may store strings of five characters
including null terminator. Note that, the declaration parameter ‘[<string size in each
row >]’ is required only at the time of array declaration. When storing and retrieving of
strings, we just ignore it or just replace it by ‘[0]’ only.
2.1. ARRAY 251

myArr[0]
0×0012 0×0013 0×0014 0×0015 0×0016

T h i s \0

myArr[1] i s \0

m y \0

myArr[3] p e t \0
0×0312 0×0313 0×0314 0×0315 0×0316

Figure 2.6:


1 # include < stdio .h >
# include < string .h >
3

int main () {
5 char myArr [4][5]={ " This " ," is " ," my " ," pet " };
printf ( " String is ’% s ’\ n " , myArr [0]) ;
7 printf ( " String is ’% s ’\ n " , myArr [1]) ;
printf ( " String is ’% s ’\ n " , myArr [2]) ;
9 printf ( " String is ’% s ’\ n " , myArr [3]) ;
return 0;
11 }
✆✌

String is ’ This ’
String is ’is ’
String is ’my ’
String is ’ pet ’
✆✌
Note that, a string variable is pointer of itself and points to address where data is stored.
So, use of ‘&’ symbol is optional. It also points to the address of first character of string,
so use of ‘[0]’ is also optional. So that, ‘myArr’ and ‘myArr[0]’ both return the string
‘This’.

# include < stdio .h >
2 # include < string .h >

4 int main () {
char myArr [4][5]={ " This " ," is " ," my " ," pet " };
6 printf ( " String is ’% s ’\ n " , myArr ) ;
printf ( " String is ’% s ’\ n " , myArr [1]) ;
8 printf ( " String is ’% s ’\ n " , myArr [2]) ;
printf ( " String is ’% s ’\ n " , myArr [3]) ;
10 return 0;
}
✆✌

String is ’ This ’
252 Array & Pointer

String is ’is ’
String is ’my ’
String is ’ pet ’
✆✌
We can also declare an array that is arranged in rows and columns and each column is of
fixed size for storing of strings.

char myArr [ < rows >][ < cols >][ < string size >]
✆✌

myArr[0][1]

myArr[0][0]
0×0012 0×0013 0×0014 0×0015 0×0016 0×0017 0×0018 0×0019 0×0020 0×0021

T h i s \0 T h a t \0

myArr[1][0] i s \0 w a s \0

m y \0 m y \0

myArr[3][0] p e t \0 p e n \0
0×0312 0×0313 0×0314 0×0315 0×0316 0×0317 0×0318 0×0319 0×0320 0×0321

Figure 2.7:

See the example below:



1 # include < stdio .h >
# include < string .h >
3

# define ROWS 4
5 # define COLS 2
# define STRING_SIZE 5
7

int main () {
9 char myArr [ ROWS ][ COLS ][ STRING_SIZE ] = {
{ " This " , " That " } ,
11 { " is " , " was " } ,
{ " my " , " my " } ,
13 { " pet " , " pen " }
};
15 int i ;
printf ( " Data matrix is : \ n " ) ;
17 for ( i = 0; i < ROWS ; i ++) {
printf ( " %5 s \ t %5 s \ n " , myArr [ i ][0] , myArr [ i ][1]) ;
19 }
return 0;
21 }
✆✌

Data matrix is :
This That
is was
2.1. ARRAY 253

my my
pet pen
✆✌
We can add new strings in this array by using strcpy function by indicating the address
of matrix cell.

1 /* At fifth row , first column */
strcpy ( arr [4][0] , " Hi " ) ;
3 /* At fifth row , second column */
strcpy ( arr [4][1] , " His " ) ;
✆✌
While we use scanf function to add user’s input from input stream, we should exactly
known to the address of memory byte where data is to be stored.

# include < stdio .h >
2 # include < string .h >

4 # define ROWS 5
# define COLS 2
6 # define STRING_SIZE 5

8 int main () {
char myArr [ ROWS ][ COLS ][ STRING_SIZE ] = {
10 { " This " , " That " } ,
{ " is " , " was " } ,
12 { " my " , " my " } ,
{ " pet " , " pen " }
14 };
int i ;
16 printf ( " Enter data for 5 th row 1 st column : " ) ;
scanf ( " % s " , myArr [4][0]) ;
18 printf ( " Enter data for 5 th row 2 nd column : " ) ;
scanf ( " % s " , & myArr [4][1][0]) ; /* last [0] is optional */
20 printf ( " Data matrix is : \ n " ) ;
for ( i = 0; i < ROWS ; i ++) {
22 printf ( " %5 s \ t %5 s \ n " , myArr [ i ][0] , myArr [ i ][1]) ;
}
24 return 0;
}
✆✌

Enter data for 5 th row 1 st column : hi
Enter data for 5 th row 2 nd column : his
Data matrix is :
This That
is was
my my
pet pen
hi his
✆✌
We can also declare a static multidimensional array by using pointers. It is declared as
254 Array & Pointer


char * myArr [ < rows >]
✆✌
Data should be assigned at the time of declaration. Pointer character ‘*’ is responsible
for dynamic allocation of memory of suitable size so that assigned data is stored in the
array. See the example below:

1 # include < stdio .h >

3 int main () {
/* Static array declaration */
5 char * myArr [2] = { " This " , " is " };
printf ( " First row string is : % s \ n " , myArr [0]) ;
7 printf ( " Second row string is : % s " , myArr [1]) ;
return 0;
9 }
✆✌

First row string is : This
Second row string is : is
✆✌

myArr[0]
0×0012 0×0013 0×0014 0×0015 0×0016

T h i s \0

myArr[1] i s \0
0×0112 0×0113 0×0114 0×0115 0×0116

Here, two strings have static storage prior to the program startup. In the initializer, the
arrays are converted to pointers to char and the words array is initialized with the pointer
values. It can not be modified during the program run. It has its own advantages as we
can access to character of string by using pointers.

# include < stdio .h >
2

int main () {
4 char * myArr [3] = { " This " , " is " };
printf ( " First row string is : % s \ n " , myArr [0]) ;
6 printf ( " Same from index 1 is : % s \ n " , ( myArr [0]+1) ) ;
return 0;
8 }
✆✌

First row string is : This
First row string from index 1 is : his
✆✌
Here, ‘myArr[0]+1’ means pointer points to the first row string at index ‘0’ and pointer
position is changed by one character position rather than next row.
2.1. ARRAY 255

myArr[0]+1
0×0012 0×0013 0×0014 0×0015 0×0016

T h i s \0

myArr[1] i s \0
0×0112 0×0113 0×0114 0×0115 0×0116

Using pointer, we can access whole string or its part of string. For example, ‘*myArry’
is the same as myArry[0]. ‘(*myArry)[0]’ is the same as **myArry, which is the first
character of the string and not the address of the string.

# include < stdio .h >
2

int main () {
4 char * myArr [2] = { " This " , " Home " };
printf ( " For ’ This ’ : % s \ n " , myArr [0]) ;
6 printf ( " For ’ Home ’ : % s \ n " , myArr [1]) ;
/* Address of ’ This ’ pointed by * myArr and *
8 * it points to address of character ’T ’ */
printf ( " For ’ This ’ : % s \ n " , * myArr ) ;
10 /* Dereference to pointer that is pointing *
* to address where string ’ This ’ is stored . *
12 * Pointer points to location of character ’T ’. */
printf ( " For ’T ’ : % c \ n " , ** myArr ) ;
14 /* same as above */
printf ( " For ’T ’ : % c \ n " , (* myArr ) [0]) ;
16 /* Dereference to pointer that is pointing *
* to address where string ’ This ’ is stored .*
18 * Pointer in incremented by one , and now , *
* it points to location of character ’h ’. */
20 printf ( " For ’h ’ : % c \ n " , (* myArr ) [1]) ;
/* same as above */
22 printf ( " For ’h ’ : % c \ n " , *(* myArr +1) ) ;
return 0;
24 }
✆✌

For ’ This ’ : This
For ’ Home ’ : Home
For ’ This ’ : This
For ’T ’ : T
For ’T ’ : T
For ’h ’ : h
For ’h ’ : h
✆✌

2.1.4 Array in Function


In functions arguments are passed to it as value unless the function needs alter the
argument. If function needs update the argument, argument should be passed to function
as its argument. Arrays can also passed to functions as pointers. If an array is passed to
256 Array & Pointer

the function, function would have to allocate enough space to hold a copy of the original
array and then copy all the data from the original array to the new array. It is much
quicker to pass the address of the array rather than array itself and have the function
work with the original data. Prototype for the passing of an array to the function is

1 int sum ( int arr [ ])
/* Or */
3 int sum ( int * arr )
✆✌

sum() S

anArray

3 6 9 12 15
i0 i1 i2 i3 i4

Figure 2.8: Passing of address of array to sum() function. Array is pointed by the
pointer/variable ‘anArray’.

In C, array parameters are always treated as pointers. C compilers do not check the
size of the array passed to the function hence for good programming, the function should
know the limits of actions on the array. This is why a new parameter of array size as ‘n’
is passed to the function as

1 int sum ( int arr [ ] , int n )
✆✌

sum()

for(i=0; i<n; i++){


S
S += anArray[i];

n
anArray

3 6 9 12 15
i0 i1 i2 i3 i4

Figure 2.9: Passing of address of array as well as element size of the array to sum()
function. Array is pointed by the pointer/variable ‘anArray’.

Because the name of an array is the address of the first element, an actual argument of
an array name requires that the matching formal argument be a pointer. In this context
int arr[ ] to mean the same as the int * arr. First bracket in the multidimensional array
may be empty or not but other brackets should contains the valid integers for the size of
the array dimension. For example
2.1. ARRAY 257


1 int sum ( int arr [ ][ ] , int rows ) ; // faulty declaration
✆✌
is a faulty declaration. Recall that the compiler converts array notation to pointer no-
tation. It means, that arr[1] will become arr+1. For the compiler to evaluate this, it
needs to know the size of object to which ‘arr’ points. The declaration

1 int sum2 ( int arr [ ][4] , int rows ) ; // valid declaration
✆✌
says that ‘arr’ points to an array of four integers, so ‘arr+1’ means “add 16 bytes to the
address”. If first bracket contains a number then it will be ignored.

1 int sum2 ( int ar [3][4] , int rows ) ; // valid declaration , 3 ignored
✆✌

1 # include < stdio .h >
# define ROWS 3
3 # define COLS 4
int sum ( int rows , int cols , int ar [ rows ][ cols ]) ;
5

int main ( void ) {


7 int i , j ;
int varr [ ROWS ][ COLS ];
9 for ( i = 0; i < ROWS ; i ++)
for ( j = 0; j < COLS ; j ++)
11 varr [ i ][ j ] = i * j + j ;
printf ( " 3 x4 Array \ n " ) ;
13 printf ( " Sum of all elements = % d \ n " ,
sum ( ROWS , COLS , varr ) ) ;
15 return 0;
}
17 int sum ( int rows , int cols , int ar [ rows ][ cols ]) {
int r ;
19 int c ;
int tot = 0;
21 for ( r = 0; r < rows ; r ++)
for ( c = 0; c < cols ; c ++)
23 tot += ar [ r ][ c ];
return tot ;
25 }
✆✌

3 x 4 Array
Sum of all elements = 36
✆✌
An array can passed to a function by using function prototype as shown in syntax given
below:

# include < stdio .h >
2

void PrintIt ( char Str [ ]) {


4 printf ( " % s \ n " , Str ) ;
258 Array & Pointer

}
6

int main () {
8 char label [ ] = " Allora Caves . " ;
PrintIt ( label ) ;
10 return 0;
}
✆✌
The output is

Allora Caves .
✆✌
Function PrintIt() expects a character array. When an array is declared as the
parameter to a function, it really gets a pointer. Arrays are always automatically passed
by reference. Similarly a pointer can also pass to a function as an array or as a pointer.

1 # include < stdio .h >

3 void PrintIt ( char Str [ ]) {


printf ( " % s \ n " , Str ) ;
5 }

7 int main () {
char * label = " Allora Caves . " ;
9 PrintIt ( label ) ;
return 0;
11 }
✆✌
The output is

Allora Caves .
✆✌

1 # include < stdio .h >

3 void PrintIt ( char * Str ) {


printf ( " % s \ n " , Str ) ;
5 }

7 int main () {
char * label = " Allora Caves . " ;
9 PrintIt ( label ) ;
return 0;
11 }
✆✌
The output is

Allora Caves .
✆✌
Unfortunately, (in C and C++) the length of the array cannot be obtained from an
array passed to a function at run time, because the size of an array is not stored anywhere.
The compiler always replaces sizeof () with a constant. See the following example
2.1. ARRAY 259


1 # include < stdio .h >
# include < string .h >
3

# define NUM_ELEM ( x ) ( sizeof ( x ) / sizeof (*( x ) ) )


5

int sum ( int input_array [ ]) {


7 int sum_so_far = 0;
int i ;
9 /* Would NOT Work ; input_array was *
* not defined in this function . */
11 for ( i = 0; i < NUM_ELEM ( input_array ) ; i ++) {
sum_so_far += input_array [ i ];
13 };
return ( sum_so_far ) ;
15 }

17 int main ( int argc , char * argv [ ]) {


int left_array [ ] = {1 , 2 , 3};
19 int right_array [ ] = {10 , 9 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 1};
int the_sum = sum ( left_array ) ;
21 printf ( " the sum of left_array is : % d \ n " , the_sum ) ;
the_sum = sum ( right_array ) ;
23 printf ( " the sum of right_array is : % d \ n " , the_sum ) ;

25 return 0;
}
✆✌
When this example is run, it gives output as shown below

the sum of left _ array is 1
the sum of right _ array is 10
✆✌
whatever the values are passed as argument in the sum function. This ‘sum()’ routine
needs to handle more than just one constant length of an array. There are some common
ways to work around this fact:
1. Write the function as required, for each array parameter and parameter “length”
which has type “size t”. We can use sizeof () at the point where this function is
called.
2. Use of a null-terminated string to mark the end of the array if array is string. Arrays
representing to numbers does not need the null-terminating string to mark of the
end of array. Instead it, number arrays are passed to the function along with its
element size.
3. Pass the arrays as well as array length parameter to the function. We can pass
the pointer-to-array if required. Evaluate the data as per rules set by function
statements or expressions.
Using these facts, above example is now modified as given below.
260 Array & Pointer


# include < stdio .h >
2

# define NUM_ELEM ( x ) ( sizeof ( x ) / sizeof (*( x ) ) )


4

int mySum ( int array [ ] , size_t length ) {


6 int sum = 0;
int i ;
8 for ( i = 0; i < length ; i ++) {
sum += array [ i ];
10 };
return ( sum ) ;
12 }

14 int main ( int argc , char * argv [ ]) {


int sum ;
16 int i_array [ ] = {10 , 9 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 1};
/* Works here , because the size of right_array *
18 * is passed to the sum function as argument */
sum = mySum ( i_array , NUM_ELEM ( i_array ) ) ;
20 printf ( " The sum is : % d .\ n " , sum ) ;

22 return 0;
}
✆✌
Output of above example is

the sum is : 55
✆✌
The same method of passing an array to a function and getting sum of all array element
is also possible with other number datatypes. Above example is suitable modified for array
contains floating type numbers.

1 # include < stdio .h >

3 # define NUM_ELEM ( x ) ( sizeof ( x ) / sizeof (*( x ) ) )

5 /* Function returns floating data . So mySum () *


* should be declared as floating data type . */
7 float mySum ( float in_array [ ] , size_t length ) {
float sum = 0;
9 int i ;
for ( i = 0; i < length ; i ++) {
11 sum += in_array [ i ];
};
13 return ( sum ) ;
}
15

int main ( int argc , char * argv [ ]) {


17 float sum ;
float array [ ] = {10.10 , 50.50 , 4.57 , 1.21};
19 sum = mySum ( array , NUM_ELEM ( array ) ) ;
2.1. ARRAY 261

printf ( " The sum is : % f \ n " , sum ) ;


21 return 0;
}
✆✌

The sum is : 66.379997
✆✌
It’s worth mentioning that sizeof () operator has two variations: sizeof (type) and sizeof (<expression>).
An example using sizeof () function to a pointer is shown below.

1 # include < stdio .h >
# include < string .h >
3

int main ( int argc , char * argv [ ]) {


5 char buffer [10];
if ( argc < 2) {
7 fprintf ( stderr , " USAGE : % s string \ n " , argv [0]) ;
return 1;
9 }
strncpy ( buffer , argv [1] , sizeof ( buffer ) ) ;
11 buffer [ sizeof ( buffer ) - 1] = ’ \0 ’;
return 0;
13 }
✆✌
Output of the script is

USAGE : executable . exe string
✆✌

2.1.5 String As Array


C has no built in string handling facilities. Consequently, string is defined as array of
characters. C allows a character array to be represented by a character string rather than
a list of characters, with the null terminating character, automatically added to the end.
Example of string array is shown below.

1 char s [ ] = { ’A ’ , ’p ’ , ’p ’ , ’l ’ , ’e ’ , ’s ’ , ’ \0 ’ };
✆✌

A p p l e s \0

Figure 2.10: Array of characters constructing word ‘Apples’ is stored in memory and
pointed by variable ‘s’.

Normally size of string array is controlled at initialisation. An string array can store only
the number of characters upto its length. Rest of the characters are ignored. In following
example only ten characters will be stored in the string array ‘mystr’.
262 Array & Pointer


1 char mystr [10] = " Apple is red . " ;
✆✌
It is convenient to let the compiler determine the array size. If one omits the size in an
initializing declaration, the compiler determines the size for supplied string. In following
example, compiler set the string length of thirteen characters.

1 char mystr [ ] = " Apple is red . " ;
✆✌
A pointer notation may aslo be set up to represent a string. In pointer notation, above
example will be look like

1 const char * ptrstr = " Delhi " ;
✆✌

ptrstr

D e l h i \0

Figure 2.11: Character array ‘Delhi’ stored in memory. ‘ptrstr’ points to the character
array ‘Delhi’.

Both declarations amount to saying that ‘ptrstr’ is a pointer to the indicated string.
Strings as array or pointer, are same but only the pointer version can use the increment
operator while array version does not support increment operator. To create an extra long
string, string is splitted into multiple sections, by closing the first section with a quote,
and recommencing the string on the next line (also starting and ending in a quote):

1 char string [ ] = " This is a very , very long "
" string that requires two lines . " ;
✆✌
See the example below

# include < stdio .h >
2

int main () {
4 char ch ;
char string [ ] = " Two lines "
6 " string . " ;
int i = 0;
8 while ( string [ i ] != ’ \0 ’) {
ch = string [ i ];
10 printf ( " % c . " , ch ) ;
i ++;
12 }
return (0) ;
14 }
✆✌
2.1. ARRAY 263


T . w . o . . l . i . n . e . s . . s . t . r . i . n . g ...
✆✌
When an array is assigned the characters to get the string, there must be a terminating
null character. Otherwise there shall be garbage output. For example following syntax
has no terminating null character. It is not in standard format.

1 char a [10];
a [0]= ’a ’;
3 a [1]= ’r ’;
a [2]= ’u ’;
✆✌
This format should be like

char a [10];
2 a [0]= ’a ’;
a [1]= ’r ’;
4 a [2]= ’u ’;
a [3]= ’ \0 ’;
✆✌
See following two examples, in which string is terminating without and with null character.
First example gives garbage output (see below).

1 # include < stdio .h >

3 int main () {
char a [10];
5 a [0]= ’a ’;
a [1]= ’r ’;
7 a [2]= ’u ’;
printf ( " % s " ,a ) ;
9 return 0;
}
✆✌

< garbage output >
✆✌
In this second example, string is terminated with null character. This example gives
output what we required.

1 # include < stdio .h >

3 int main () {
char a [10];
5 a [0]= ’a ’;
a [1]= ’r ’;
7 a [2]= ’u ’;
a [3]= ’ \0 ’;
9 printf ( " % s " ,a ) ;
return 0;
11 }
✆✌
264 Array & Pointer


aru
✆✌
Size of static array should be larger by one to the original data size being stored in the
array. This extra byte is for NULL terminator, i.e. \0. To store one byte data, array size
should be larger than one. For storing n byte data, array size should be > n. Here two
examples are given. In first example, array size is equal to the data size and in second
example, array size is larger than data size by one. This extra one byte is used to store
null terminating character.

1 # include < stdio .h >
# include < stdlib .h >
3

int main ( void ) {


5 /* Deficient static array *
* size declared as char c . */
7 char c [1];
printf ( " Enter char ’e ’ : " ) ;
9 gets ( c ) ;
if (( strcmp (c , " e " ) == 0) )
11 printf ( " % s \ n " , c ) ;
return 0;
13 }
✆✌
On compilation, it gives error while following example gives desired output.

1 # include < stdio .h >
# include < stdlib .h >
3

int main ( void ) {


5 /* Suficient static array *
* size declared as char c . */
7 char c [2];
printf ( " Enter char ’e ’ : " ) ;
9 gets ( c ) ;
if (( strcmp (c , " e " ) == 0) )
11 printf ( " % s \ n " , c ) ;
return 0;
13 }
✆✌

e
✆✌
In first example, array ‘c’ can store only character ‘c’. There is no extra space to store
null terminating character. It makes that array ‘c’ does not hold string in proper format.
In second example, array ‘c’ can store one character as well as null terminating character.
By this way it holds string in proper format.

2.1.6 Size of Array


C features two kinds of arrays: static (compile-time, fixed size) and dynamic (allocated
at run-time). The length of a dynamic array cannot be acquired from the array itself -
2.1. ARRAY 265

its length must be stored elsewhere. The size of static array is computed as

1 int length = sizeof ( < array name >) / sizeof ( < array element >) ;
✆✌
Preprocessor ways for array length is defined as

1 # define ARRAY_LENGTH ( A ) ( sizeof ( A ) / sizeof ( A [0]) )
✆✌

n
anArray

3 6 9 12 15
i0 i1 i2 i3 i4

Figure 2.12: Size of ‘anArray’ is the number of elements pointed by ‘anArray’. Here
remember that array is of integer type, hence each element shown in this figure needed
4 bytes long memory space. There are 5 elements in this array, so size of ‘anArray’ is 5
(n = 5) and these elements needed 5 × 4 = 20 bytes long memory space.

Array becomes pointer when it is passed as a parameter to a function. Thus, the length of
an array parameter may not require directly but a dedicated length parameter is required
and should be passed to the function. See the following example is given string array
‘fruit’ is declared with static size of 2 elements in each row while each row is pointed by
‘fruit’ pointer itself. Hence the element size is fixed so, there is no need to calculate the
length size of array. But in this example, length is computed by using above syntax.

1 # include < stdio .h >

3 int main () {
const char * fruit [2] = { " apples " , " oranges " };
5

/* Length of the array by dividing *


7 * the size of all elements by the *
* size of the first element . */
9

int length = sizeof ( fruit ) / sizeof ( fruit [0]) ;


11

printf ( " % d \ n " , length ) ;


13

return 0;
15 }
✆✌

2
✆✌
In above example, length of the array is obtained by dividing the size of all elements
(found with sizeof (fruit)) by the size of the first element. Note that since the array
elements are pointers to null-terminated character arrays, the size of the first element is
actually the size of the pointer type - not the length of the string. This size, regardless
of the type being pointed to, is 8 bytes, 4 bytes, or 2 bytes on 64-bit, 32-bit, or 16-bit
266 Array & Pointer

platforms respectively. Pointer can be used for variable size array as shown in example
below.

1 # include < stdio .h >
/* Variable size array . */
3 char * name ;
int main () {
5 name = " My School !! " ;
int i =0;
7 while ( name [ i ] != ’ \0 ’) {
printf ( " % c \ n " , name [ i ]) ;
9 i ++;
}
11 return 0;
}
✆✌

M
y

S
c
h
o
o
l
!
!
✆✌

2.1.7 Vector & Matrix


Vector is a one dimensional array or a matrix having one rows and multiple columns. A
vector is represented by A = [1, 2, 3, 5]. A matrix is vertical arrangement of vectors. Vec-
tors are one dimensional arrangement of coefficients of variables of an algebraic equation.
Let an algebraicequation ax + by = k, that is written as

ax + by − k = 0

Now, vector u for this algebraic equation is given by

u = [a, b, −k]

If there is a set of two algebraic equations,

ax + by − k =0
cx + dy − l =0

Then two vectors of these two algebraic equations are u and v respectively as

u = [a, b, −k]; v = [c, d, −l]


2.1. ARRAY 267

The matrix arrangement like AX = B is


 
  x  
a b −k  y = 0
c d −l 0
1

Here, matrix A is row arrangement of two vectors u and v. Similarly, for example, vectors
A = [1, 2, 3, 5] and B = [5, 4, 3, 2] form a matrix when these vectors are arranged vertically.

1 2 3 5
C =
5 4 3 2

Here, C is a 2 × 4 matrix. A one dimensional vector is defined in C like



# include < stdio .h >
2

int main ( void ) {


4 int A [5];
int i ;
6 for ( i = 1; i < 5; i ++) {
A[i] = i;
8 }
for ( i = 1; i < 5; i ++) {
10 printf ( " % d \ t " , A [ i ]) ;
}
12 return 0;
}
✆✌

1 2 3 4
✆✌
A matrix is defined in C like

1 # include < stdio .h >

3 int main ( void ) {


int A [2][5];
5 int i , j ;
for ( i = 0; i < 2; i ++) {
7 for ( j = 0; j < 4; j ++) {
A [ i ][ j ] = i + j ;
9 }
}
11 for ( i = 0; i < 2; i ++) {
for ( j = 0; j < 4; j ++) {
13 printf ( " % d \ t " , A [ i ][ j ]) ;
}
15 printf ( " \ n \ n " , A [ i ][ j ]) ;
}
17 return 0;
}
✆✌
268 Array & Pointer


0 1 2 3

1 2 3 4
✆✌
In C, arrays, vectors and matrices are defined in same ways.

2.1.8 Sparse Matrix


A sparse matrix is one which have majority number of zeros along rows and columns. For
example a sparce matrix is
 
0 0 0 0 0
 0 1 2 0 1 
 
S=  0 2 1 0 2 

 0 0 0 0 0 
0 1 2 0 1

C program for sparse matrix is given below:



1 # include < stdio .h >
# include < time .h >
3

int main () {
5 time_t t1 , t2 ;
t1 = time ( NULL ) ;
7 static int array [10][10];
int i , j , m = 5 , n = 5;
9 int counter = 0;
for ( i = 0; i < m ; ++ i ) {
11 for ( j = n ; j > 0; -- j ) {
t2 = time ( NULL ) ;
13 array [ i ][ j ] = ( i * j + t2 ) % ( t1 % 5 + 1) ;
if ( array [ i ][ j ] == 0) {
15 ++ counter ;
}
17 }
}
19 printf ( " Matrix is : \ n " ) ;
for ( i = 0; i < m ; ++ i ) {
21 for ( j = 0; j < n ; ++ j ) {
printf ( " % d \ t " , array [ i ][ j ]) ;
23 }
printf ( " \ n " ) ;
25 }
if ( counter > (( m * n ) / 2) ) {
27 printf ( " Matrix is sparse matrix \ n " ) ;
} else {
29 printf ( " Matrix is not a sparse matrix \ n " ) ;
}
31 printf ( " There are % d number of zeros .\ n " , counter ) ;
2.2. POINTER 269

return 0;
33 }
✆✌
Above proram uses the current CPU time so each time when program is run, a different
matrix is generated. The matrix generated may be a sparse matrix or not. The one run
state matrix generated by above program is given below, which is not a sparse matrix.

Matrix is :
0 4 4 4 4
0 0 1 2 3
0 1 3 0 2
0 2 0 3 1
0 3 2 1 0
Matrix is not a sparse matrix
There are 4 number of zeros .
✆✌

2.2 Pointer
A pointer is a simple variable that stores the address (the location in memory) of a value
in memory rather than storing data itself. A variable is said to be declared as a pointer
if it prefixed with an asterisk symbol. A variable name with prefixed ampersand (&)
defines the address of itself. A pointer with prefixed asterisk, except declaration, refers to
the value of the variable whose address is pointed-by the pointer. The address to which
pointer points is called pointee address.

pointee address

0×0504
0×50 0×51 0×52 0×53 0×54 0×55 0×56 0×57 0×58 0×59

int *i; pointer address

There are two valid pointer operations, (i) comparison of two pointers and (ii) addi-
tion or subtraction. Address of memory cell and value stored at that memory cell both
constitute different meanings. Memory is array of many bits which is capable of storing
values either binary 1 or binary 0. This size of memory has no meaning as it can not store
large numeric value, so multiple bits are grouped to form bytes (one byte has 8 bits). Too
store an integer, 4 bytes (32 bits) are grouped together. See the following constitution of
memory cells.

Value at memory cell

00000000 00000000 00000011 11101001


0×1001 0×1005 0×1009 0×1013

Address of memory cell


270 Array & Pointer

In which, each memory cell or memory location is identified by its address and it
contains a value. See an example given below. Read program line-by-line alongwith
comments carefully.

# include < stdio .h >
2 int main () {
/* i points to memory location where 10 is stored . */
4 int i =10;

6 /* Pointer j points to a random address */


int * j ;
8

/* Now j points to same address as i is pointing . */


10 j =& i ; // i and j points to same address .

12 /* j stored value at its address . */


* j =20;
14

/* As i and j points to same memory location *


16 *( addresses ) therefore , values of i and j *
* are equal . So , i = 20. */
18 printf ( " % d " ,i ) ; // i has same value as j ;
return 0;
20 }
✆✌

20
✆✌
An array name is also the address of the first element of the array. That is, if ‘arr’ is an
array, then

1 arr == & arr [0]; // name of array is the
// address of the first element
✆✌
Both ‘arr’ and ‘&arr[0]’ represent the memory address of first element of the array. It is
also called the reference of the array ‘arr’. A pointer can points to any element of the
array, if the pointer is assigned address of that element. In the following example, pointer
‘x’ points to the address of first element of the array ‘i’.

# include < stdio .h >
2

int main () {
4 int i [5] = {10 , 20 , 30 , 40 , 50};
int * x = & i [0]; /* Points to first element . */
6 printf ( " % d " , * x ) ;
return 0;
8 }
✆✌
2.2. POINTER 271

0×10 0×11 0×12 0×13 0×14

i[ ] 10 20 30 40 50

The output of above program shall be



10
✆✌
If above example is modified as given below, then the pointer ‘x’ points to the 3rd
element of the array ‘i’.

1 # include < stdio .h >

3 int main () {
int i [5] = {10 , 20 , 30 , 40 , 50};
5 int * x = & i [2]; /* Points to third element . */
printf ( " % d " , * x ) ;
7 return 0;
}
✆✌

0×0 0×1 0×2 0×3 0×4

i[ ] 10 20 30 40 50

The output of above program shall be



30
✆✌
If an integer is pointed by a pointer-to-char variable, then this variable can points to
the address of each byte of the integer variable (integer variable is 4 bytes long).

1 # include < stdio .h >

3 int main () {
/* 1000 D = 1111101001 B */
5 int i = 1001;
/* Pointer casting from integer to character . */
7 char * x = ( char *) & i ;
/* Little endian is x [0]=11101001 B *
9 * Big endian is x [1]=00000011 B *
* Big endian x [2]= x [3]=00000000 B */
11 /* Print little endian x [0] */
printf ( " % d " , ( int ) x [0]) ;
13 return 0;
}
✆✌
272 Array & Pointer

i: 00000000 00000000 00000011 11101001


x[3] x[2] x[1] x[0]

Output of above program is



-23
✆✌

1 # include < stdio .h >

3 int main () {
/* 1000 D = 1111101001 B */
5 int i = 1001;
/* Pointer casting from integer to character . */
7 char * x = ( char *) & i ;
/* Little endian is x [0]=11101001 B *
9 * Big endian is x [1]=00000011 B *
* Big endian x [2]= x [3]=00000000 B */
11 /* Print big endian x [1] */
printf ( " % d " , ( int ) x [1]) ;
13 return 0;
}
✆✌

i: 00000000 00000000 00000011 11101001


x[3] x[2] x[1] x[0]

Output of above program is



3
✆✌
Though, the pointers allow increment and decrement operations but they are not
preferred over indexed arrays when there is requirement of random access. In indexed
arrays, fifth element can be accessed by myArr[4]. But in pointer array, we have to
first reach at the address of fifth element by using pointer increments or decrements
operations and then dereference the pointer. So, pointer requires extra coding to reach
at desire destination.
Identification of Pointer Type We know that, in C, a variable is declared as

1 < datatype > < var name >;
✆✌
There are three main form of variable object declarations. (i) normal variables, (ii) arrays
and (iii) functions. Their prototypes are respectively
2.2. POINTER 273


1 int i ; // normal variable
int k [10]; // array variable
3 int f () ; // function variable
✆✌
In above three declarations, priority is observed to identify the type of variable. In first
case, variable ‘i’ is normal integer type variable which stores integer values. It means
where ever it stores a value, it will be an integer. Priority of variable literal is lower
than square brackets or parentheses. A variable is followed by square brackets, then it is
treated as an array. Similarly, if a variable is followed by parentheses, then it is treated
as function. Now, the question is, how we identify the nature of variable when asterisk is
prefixed to variable literals to make it pointer variable as shown below:

1 int * i ;
int * k [10];
3 int * f () ;
✆✌
Its answer is again priority listing. The priority of pointer symbol (asterisk) is less than
array symbol or parentheses. Hence first declaration is pointer to integer. In second
declaration, priority of variable ‘k’ goes with array symbol and asterisk makes it pointers.
Hence, it will be pronounce as “array k of pointers-to-integers”. Note that, datatype only
told about the type of data pointed by the pointers, not about the type of pointer itself.
Similarly, third declaration is “function which returns a pointer pointing-to-an-integer
value”. Remember, array always stores values and function always returns a value. Now,
parentheses are used to change the priority of asterisk like

1 int * i ;
int (* k ) [10];
3 int (* f ) () ;
✆✌
The first declaration has no change. It is pointer to an integer. In second declaration,
priority of asterisk goes with ‘k’. Hence it is pronounce as “pointer ‘k’ to an array (due
to presence of square bracket) of integers (array stores integer type values)”. Similarly
third declaration is pronounced as “pointer ‘f’ points to a function (due to presence of
parentheses) which returns an integer value”. So, be careful while using pointers with
specific priorities. There is not change in the priority if data type is changed. For example,
only stored value at pointee address is changed to real (double data type) from integer if
above declaration is modified as

1 double * i ;
double (* k ) [10];
3 double (* f ) () ;
✆✌

2.2.1 Declaring pointers


When a variable name is preceded by asterisk symbol during its declaration, it is called
pointer variable. In the following variable declarations:
274 Array & Pointer


1 long * var1 , var2 ; // Declaration of pointer
int ** p3 ; // Declaration of pointer to a pointer
✆✌
In line 1, ‘var1’ is declared as a pointer variable to a long data type, i.e. data stored
at the pointed-to address will be long data type. And ‘var2’ is declared as a long data
type variable and it is not a pointer to a long data type as it is not preceded by asterisk
symbol. In line 2, ‘p3’ is declared as a pointer to a pointer to an int data type. Data
types which precedes to a pointer variable during pointer declaration specify about the
data read or write at the address pointed-to by the pointer variable. If data type is char
type, then will be read at the address location in group of one byte. If data type is int
type, then data will be read at the address location in group of four bytes and so on.
Remember that uninitialized pointers results in dangling or wild pointers, therefore each
pointer declared must be initialized as NULL pointer.

int * p = NULL ; // Declaration & initializat io n of pointer
✆✌
It is also safe to initialized a pointer to NULL when its allocated memory is freed by
using free() function.

1 int * p = NULL ; // Declaration & initializat io n of pointer
p = malloc (10) ; // Allocate memory space
3 free ( p ) ; // Free memory space allocated to pointer
p = NULL ; // Initialize NULL to pointers
✆✌
Pointer types are often used as parameters to function calls.

int MyFunction ( struct MyStruct * pStruct ) ;
✆✌
In the above syntax, it is explained that how to declare a function which uses a pointer as
an argument. Since C passes function arguments by value, in order to allow a function to
modify a value from the calling routine, a pointer to the value must be passed. Pointer-
to-Structure is also used as function arguments even when nothing in the struct will be
modified in the function. This is done to avoid copying the complete contents of the
structure onto the stack. A simple example is

1 # include < stdio .h >
# include < time .h >
3 void getSeconds ( unsigned long * par ) ;

5 int main () {
unsigned long sec ;
7 getSeconds (& sec ) ;
printf ( " No . of seconds since 01 Jan 1970: % ld \ n " , sec ) ;
9 return 0;
}
11

void getSeconds ( unsigned long * par ) {


13 * par = time ( NULL ) ;
return ;
15 }
✆✌
2.2. POINTER 275


No . of seconds since 01 Jan 1970: 1420616845
✆✌

Solved Problem 2.1 See the following memory arrangement. A pointer variable is declared
and assigned address as given in below code lines. What will be the print output?
Solution The memory arrangement is :

00000000 00000000 10010101 10110101 10110101 11111111 10011101 10101101 10010001

0×51 0×52 0×53 0×54 0×55 0×56 0×57 0×58 0×59


1 char * ptr =0 x53 ;
printf ( " % d " , * ptr ) ;
✆✌
Here, pointer is declared as char type, hence it shall read data stored at address 0×53 in
a group of one byte (byte group size is equal to the size of char data type).

00000000 00000000 10010101 10110101 10110101 11111111 10011101 10101101 10010001

0×51 0×52 0×53 0×54 0×55 0×56 0×57 0×58 0×59

So, the printf function will give output in decimal form which is equal to the value
stored at the address of 0×53. From the memory arrangement, value is 100101012, that
is decimal equivalent to 14910.

Solved Problem 2.2 See the following memory arrangement. A pointer variable is declared
and assigned address as given in below code lines. What will be the print output?

Solution The memory arrangement is :

00000000 00000000 10010101 10110101 10110101 11111111 10011101 10101101 10010001

0×51 0×52 0×53 0×54 0×55 0×56 0×57 0×58 0×59


short * ptr =0 x53 ;
2 printf ( " % d " , * ptr ) ;
✆✌
Here, pointer is declared as short type, hence it shall read data stored at address 0×53 in
a group of two bytes (bytes group size is equal to the size of short data type).

00000000 00000000 10010101 10110101 10110101 11111111 10011101 10101101 10010001

0×51 0×52 0×53 0×54 0×55 0×56 0×57 0×58 0×59

So, the printf function will give output in decimal form which is equal to the value
stored in two consecutive bytes whose first byte is at the address of 0×53. From the
memory arrangement, value is 10010101101101012, that is decimal equivalent to 3832510.
276 Array & Pointer

Solved Problem 2.3 See the following memory arrangement. A pointer variable is declared
and assigned address as given in below code lines. What will be the print output?
Solution The memory arrangement is :

00000000 00000000 10010101 10110101 10110101 11111111 10011101 10101101 10010001

0×51 0×52 0×53 0×54 0×55 0×56 0×57 0×58 0×59


short * ptr =0 x53 ;
2 printf ( " % d " , *( ptr ++) ) ;
✆✌
Here, pointer is declared as short type, hence it will point to address of data stored from
address 0×53 onward in a group of two bytes (bytes group size is equal to the size of short
data type). The increment of pointer ‘ptr++’ will increase the address pointed by the
pointer variable ‘ptr’ by two bytes (equal to the size of declaration data type, here it is
short ).

00000000 00000000 10010101 10110101 10110101 11111111 10011101 10101101 10010001

0×51 0×52 0×53 0×54 0×55 0×56 0×57 0×58 0×59

Thus the address pointed by the pointer variable ‘ptr’ is 0×55. So, the printf function
will give output in decimal form which is equal to the value stored in two consecutive
bytes whose first byte is at the address of 0×55. From the memory arrangement, value is
10110101111111112, that is decimal equivalent to 4659110.

Assigning values to pointers


A pointer variable points to an address. So, its value is always an address of other
variable. The address of a variable is accessed by using ‘address of’ operator, represented
by symobl ‘&’. The standard procedure of assigning value to a pointer variable is shown
in the following code snippets.

/* An interger variable that have *
2 * null value stored in memory . */
int myInt ;
4 /* Pointer that addresses to a integer value . */
int * ptr ;
6 /* Address to the pointer where *
* myInt value is stores in memory . */
8 ptr = & myInt ;
✆✌
Here, ‘ptr’ will now reference to ‘myInt’. Pointers can also be assigned to dynamically
allocated memory. See the following example.

# include < stdio .h >
2 int j , k ;
int * ptr ;
4
2.2. POINTER 277

int main ( void ) {


6 j = 1;
k = 2;
8 ptr = & k ;
printf ( " j has value % d and stored at % p \ n " , j , ( void *) & j ) ;
10 printf ( " k has value % d and stored at % p \ n " , k , ( void *) & k ) ;
printf ( " ‘ ptr ’ = % p and stored at % p \ n " , ptr , ( void *) & ptr ) ;
12 printf ( " Value of the integer pointed - by ‘ ptr ’ is % d \ n " , * ptr ) ;
return 0;
14 }
✆✌

j has value 1 and stored at 0 x 403100
k has value 2 and stored at 0 x 403120
‘ ptr ’ has value 0 x 403120 and stored at 0 x 403110
Value of the integer pointed - by ‘ ptr ’ is 2
✆✌

&k
0×50 0×51 0×52 0×53 0×54 0×55 0×56

int *ptr = &k 2 3 4 5 6 7 8

A pointer is created by using asterisk (*) as shown in the first line of the below code.
Method of value assignment to the variable is shown in second line of the following code.

int * j ;
2 j = 5; /* Valid & good practice . */
✆✌
This type of assignment updated value stored at the address of pointer variable itself. In
above type of pointer assignment, pointer now points to the memory whose address is
0×05. See the example

# include < stdio .h >
2

int main () {
4 int * j ;
j = 5; /* Valid & good practice .*
6 * It accepts address . */
printf ( " j is : % d \ n " , j ) ; // prints address pointed
8 // by the pointer variable
return 0;
10 }
✆✌

j is : 5
✆✌
As pointers holds the address of other variables or objects, hence what ever value is
assigned to pointers is treated as memory address. Note that, addresses are represented
278 Array & Pointer

in hexa-decimal form, hence all other values are converted into equivalent hexadecimal
values. Method of assigning a value to a pointer as shown below is invalid. This is due to
assigning value to an uninitialised pointer. An uninitialized pointer points to null memory
address. So, when we tries to update the value at the memory address that is pointed by
the pointer, it shows errors.

1 int * j ; // No address with pointer to point .
* j = 5; /* Invalid as it tries to alter value *
3 * stored at address pointed by j . *
* It is very bad practice . */
✆✌
A pointer points to the memory location (address) where value is stored. Pointer does
not store value itself. So, pointer does not know where value is stored. If we try to do so,
the program either may crash or it damaged to the system. A best practice of assigning
a pointer is explained in the following example.

# include < stdio .h >
2

int main () {
4 int i = 0;
int * j ;
6 j = malloc (2 * sizeof ( int ) ) ;
j = 5; /* valid & good practice to assign address */
8 printf ( " j is : %d\n", j ) ; // prints address
j = 6; /* valid & good practice to assign address */
10 printf ( " j is : %d\n", j ) ; // prints address
return 0;
12 }
✆✌

j is : 5
j is : 6
✆✌
Another example

# include < stdio .h >
2

int main ( void ) {


4 int i ;
int * p ;
6 p = & i ; /* valid for best practice */
i = 10; /* i is now 10 */
8 * p = 20; /* valid */
/* prints 20 */
10 printf ( " i is % d \ n " , i ) ;
/* Prints value stored at address pointed by the pointer . */
12 printf ( " i is % d \ n " , * p ) ;
return 0;
14 }
✆✌
2.2. POINTER 279


i is 20
i is 20
✆✌

Pointer Dereferencing (Value Finding)


Pointer dereferencing or value finding or indirection is a method to extract the value stored
at given memory address. To access a value to which a pointer points, the ‘*’ operator
is used. Another operator, the ‘–>’ operator is used in conjunction with pointers to
structures. To understand dereferencing, take a memory arrangement as shown below:

A B C D E F G H I
0×11 0×12 0×13 0×14 0×15 0×16 0×17 0×18 0×19

Now, we declare a pointer and assign an address as



char * x = 22;
2 printf ( " % c " , * x ) ;
✆✌

∗x
00010110
0×2A

It does not gives character whose character code is equal to 22 but it gives the character
that is stored at address of 0×16 (decimal 22 and binary 00010110). And from the above
memory arrangement, it is character F . There can use ‘&’ and ‘*’ alternatively. Here
operator ‘*’ is used for dereferencing and the operator ‘&’ is used to get the address.
When they are used in group, they cancel the effect of each other. See the example
below:

# include < stdio .h >
2

int main () {
4 char * p = " Lucknow is capital city of UP . " ;
/* See the sequence of & and *. */
6 printf ( " % s \ n " , &*&* p ) ;
char * q = " Delhi is capital city of India . " ;
8 /* Sequence of & and * is changes */
printf ( " % s \ n " , *&*& q ) ;
10 return 0;
}
✆✌

Lucknow is capital city of UP .
Delhi is capital city of India .
✆✌
Again see the modified form of above example.
280 Array & Pointer


# include < stdio .h >
2

int main () {
4 char * p = " Lucknow is capital city of UP . " ;
printf ( " % c \ n " , *&*&* p ) ;
6 return 0;
}
✆✌

L
✆✌
Here, ‘p’ is a pointer to first character of string, which is L. *p gives us L, &*p gives
address of L, *&*p again L, &*&*p address of L, and finally *&*&*p gives ‘L’. In case
of integer type variables, variables points to the address where integer value is stored.
When integer type variables are passed to function as its parameter, then we can either
pass the value of the integer type variable or address of the variable. Address of integer
type variable is fetched by using ‘&’ symbol while the value at the address is catch by
using ‘*’ symbol.

1 # include < stdio .h >

3 /* Catch value of i as j . Catch the *


* value of from address of i as k . */
5 void catchI ( int j , int * k ) {
/* The value of parameter k is not *
7 * assigned to any integer variable ,*
* hence when we want to print it , *
9 * it must be dereferece first as k *
* is still pointing to address of i */
11 printf ( " % d % d \ n " , j , * k ) ;
}
13

int main () {
15 int i = 3;
catchI (i , & i ) ;
17 return 0;
}
✆✌

3 3
✆✌
Now, a question rises that do we can access the value stored at memory by referencing
to its address? For example, consider memory arrangement as shown below:

Value at memory cell

00000000 00000000 00000011 11101001


0×1001 0×1005 0×1009 0×1013

Address of memory cell (&i)


2.2. POINTER 281

A variable (i) points to the address of 0×1013 where data 11101001 is stored in binary
format. When we reference to variable (i), we get the value 233 in decimal. Do we can
find the value by dereferencing ∗0×1013? The answer is NO, because, 0×1013 is pure
integer and dereferencing can only performed on expression of type pointer. So, to get
the value from the address 0×1013 we should type cast it like

1 *( int *) 0 x1013
✆✌
Note that, while we access memory address directly, the System OS may prevent to do
so due to memory sharing violation or access violation. See the example below, in which
printf tries to print the value stored at address 102010 which is primarily reserved for the
application of OS.

1 # include < stdio .h >

3 int main ( int argc , char ** argv ) {


printf ( " % d .\ n " ,*( int *) 1020) ;
5 }
✆✌

Addition of pointers
Following is an example in which addition of a pointer and an integer is explained.

1 # include < stdio .h >
/* Note that it accepts a pointer to an int */
3 void increment ( int * p ) {
* p = * p + 1; /* dereference p and add 1 */
5 }

7 int main ( void ) {


int i = 20;
9 /* i value is 20 */
printf ( " i is % d \ n " , i ) ;
11 /* Pass integer to increment function as pointer */
increment (& i ) ;
13 /* Prints the value 21 */
printf ( " i is % d \ n " , i ) ;
15 return 0;
}
✆✌

i is 20
i is 21
✆✌
The value of a pointer is the address of the object to which it points. The address of a
large object, such as type double variable, typically is the address of the first byte of the
object. Applying the * operator to a pointer yields the value stored in the pointed-to
object. Adding 1 to the pointer increases its value by the size, in bytes, of the pointed-to
type. In following prototypes
282 Array & Pointer


arr + 2 == & arr [2] /* Same address */
2 *( arr + 2) == arr [2] /* Same value */
✆✌
Again *(arr+2) with *arr+2 are different to each other. The indirection operator (*)
binds more tightly (that is, has higher precedence) than +.

*( arr + 2) /* Value of the 3 rd element of dates */
2 * arr + 2 /* 2 added to the value of the 1 st element */
✆✌
Pointer address can be changed by using pointer increments. If ‘a’ is a pointer address
then ‘a++’ shall be next pointer address. The increments or decrements is equal to the
size of data type of pointer. For example, if pointer addresses to a character data type,
then its jump is multiple of four bytes. If pointer addresses to an integer data type, then
its jump is multiple of one byte. In the following example, the pointer address of pointer
‘name’ is increased by one byte and the value at that pointer location is retrieved and
printed in console output.

# include < stdio .h >
2 /* Pointer array . */
char * name ;
4 int main () {
name = " My School !! " ;
6 /* While pointer value is not null . */
while (* name != ’ \0 ’) {
8 /* Print the pointer value . */
printf ( " % c \ n " ,* name ) ;
10 /* Increase the pointer location . */
name ++;
12 }
return 0;
14 }
✆✌

M
y

S
c
h
o
o
l
!
!
✆✌
Now a question rises, what happen if a pointer reaches beyond the string length. Answer
is, that it starts pointing to the any string supplied as stdin by program itself or by user.
Escape characters if present are skipped. See the example below:

1 # include < stdio .h >
2.2. POINTER 283

/* Pointer array . */
3 char * name ;

5 int main () {
name = " My School " ; /* string length is 11 */
7 int i = 0;
/* Points to 20 characters started *
9 * from 0 location of name pointer . */
while ( i < 20) {
11 /* * name first puts the value of *
* string while i <=11. When the *
13 * supplied string is ended , it *
* starts pointing to the stdin *
15 * string " Value at pointer ....." */
printf ( " Value is : % c \ n " , * name ) ;
17 /* Increase the pointer location . */
name ++;
19 i ++;
}
21 return 0;
}
✆✌

Value is : M
Value is : y
Value is :
Value is : S
Value is : c
Value is : h
Value is : o
Value is : o
Value is : l
Value is :
Value is : V
Value is : a
Value is : l
Value is : u
Value is : e
Value is :
Value is : i
Value is : s
Value is :
Value is : :
✆✌
See another example given below.

# include < stdio .h >
2 /* Pointer array . */
char * name ;
4

int main () {
6 name = " My School !! " ;
284 Array & Pointer

int i = 0;
8 /* While pointer value is not null . */
while (* name != ’ \0 ’) {
10 /* If i is larger than 5. */
if ( i > 5) {
12 /* Decrease the pointer location by 5. */
name = name - 5;
14 /* Reset i . */
i = 0;
16 /* Print new line . */
printf ( " \ n " ) ;
18 }
/* Print the pointer values . */
20 printf ( " % c " , * name ) ;
/* Increase the pointer location . */
22 name ++;
/* Increase i by one . */
24 i ++;
}
26 return 0;
}
✆✌

My Sch
y Scho
Schoo
School
chool !
hool !!
✆✌

Passing of Pointers
Value assigned to one pointer can be passed to other pointer. Actually, values of both
pointers are not copied mutually but pointers are set to point the value of other pointer.
See the example given below:

# include < stdio .h >
2 # include < stdlib .h >

4 int main () {
/* Pointer array . */
6 int * x ,* y , *z , i =0;
x = malloc ( sizeof ( int ) *100) ;
8 y = malloc ( sizeof ( int ) *100) ;
while (i <10) {
10 x[i] = i;
y [ i ] = 3* i ;
12 i ++;
}
14 i =0;
printf ( " Original data is : \ nx \ t y \ n " ) ;
2.2. POINTER 285

16 while ( i < 5) {
printf ( " % d \ t " , x [ i ]) ;
18 printf ( " % d \ t " , y [ i ]) ;
printf ( " \ n " ) ;
20 i ++;
}
22 /* Mutually transfer the pointers . */
z =& x [0];
24 x =& y [0];
y =& z [0];
26 i =0;
printf ( " \ nPassing the Pointer , data is : \ nx \ t y \ n " ) ;
28 while ( i < 5) {
printf ( " % d \ t " , * x ) ;
30 printf ( " % d \ t " , * y ) ;
printf ( " \ n " ) ;
32 x ++;
y ++;
34 i ++;
}
36 return 0;
}
✆✌

Original data is :
x y
0 0
1 3
2 6
3 9
4 12

Passing the Pointer , data is :


x y
0 0
3 1
6 2
9 3
12 4
✆✌

2.2.2 Pointers and Arrays


String is an array of characters. In other words, an array contains arranged characters
one after another. For example

1 char label [ ] = " Single " ; /* implicitly representati on */
✆✌
arranges characters in memory as
286 Array & Pointer

S i n g l e \0

Memory location of the array may be anywhere. The location of array is known as
address of the string. Here ‘\0’ is null character represents to the end of string. The
available spaces (size) of a character array may be larger than the number of characters
of abstract string to be held in it. See the example given below.

1 char label [10] = " Single " ; /* explicitly representati on */
✆✌
Characters are arranged in memory like

S i n g l e \0 \0 \0 \0

In above type of representation of array is called static representation, because size


of allocated memory or size of array is determined at the time of program compilation.
When size of array is specified, the number of elements is at least one more than the
length of string. Any unused elements are automatically initialized to null character ‘\0’.
Pointer can hold only an address and they cannot hold all the characters of the character
array. It means, special symbol ‘*’ (asterisk) is used to keep track of a string rather than
string itself.

1 char name [ ] = " Arun " ;
char status [10] = " Married " ;
3 char * Ptr ;
Ptr = name ;
✆✌
The first memory byte of the above variables, i.e. ‘name’, ‘status’ and ‘Ptr’ assumed to
be at the location 0×40, 0×50 and 0×60 respectively. The memory arrangement for the
‘name’ variable will be as

A r u n \0
0×40 0×41 0×42 0×43 0×44

The memory arrangement of the variable ‘status’ will be as

M a r r i e d \0 \0 \0
0×50 0×51 0×52 0×53 0×54 0×55 0×56 0×57 0×58 0×59

and memory arrangement of the pointer variable ‘Ptr’ with holding the address of the
variable ‘name’ will be looked like:

0×40
0×60 0×61 0×62
2.2. POINTER 287

During the assignment of a pointer to the address of a string array, the pointer must
be a character pointer (type of data it points at the address it stored). To assign the
address of an array to a pointer, address-of (&) operator is not used since the name of an
array behaves like an address of that array in this context (array name, either string or
integer, acts as address itself). A pointer is a non constant pointer1 that points to a non
constant string2 where as arrays is a constant pointer3 which points to a non constant
string4 . The interaction of pointers and arrays have two fundamental statements about
them.
1. A variable declared as an array of some type acts as a pointer to that type. When
used by itself, it points to the first element of the array.
2. A pointer can be indexed like an array name.
Often, the first case is seen when an array is passed to a function as an argument. The
function declares the parameter as a pointer, but the actual argument may be the name
of an array. The second case occurs when dynamically allocated memory is accessed.
Pointer reference example is given below.

# include < stdio .h >
2 int main () {
int a [10] , * iptr ;
4 iptr = a ;
* iptr = 5; // update the value of a [0]
6 printf ( " The first element is % d " , iptr [0]) ;
return 0;
8 }
✆✌

The first element is 5
✆✌
A function which can accept a pointer, can also accept an array. Pointers also follow the
rules of array and array increment processing.

1 # include < stdio .h >
int my_array [ ] = {1 ,23 ,17 ,4 , -5 ,100};
3 int * ptr ;
int main ( void ) {
5 int i ;
/* Point our pointer to the *
7 * first element of the array */
ptr = & my_array [0];
9

for ( i = 0; i < 6; i ++) {


11 printf ( " my_array [% d ] = % d " , i , my_array [ i ]) ;
printf ( " ptr + % d = % d \ n " , i , *( ptr + i ) ) ;
1
The address it holds can be updated/changed.
2
String size is dynamic as pointer points to the address of first character of string.
3
Array name always points to that address at which its data is stored. This address can not be
changed as if it is changed, array name starts pointing to something else.
4
String size is dynamic as pointer points to the address of first character of string.
288 Array & Pointer

13 }
return 0;
15 }
✆✌

my _ array [0] = 1 ptr + 0 = 1
my _ array [1] = 23 ptr + 1 = 23
my _ array [2] = 17 ptr + 2 = 17
my _ array [3] = 4 ptr + 3 = 4
my _ array [4] = -5 ptr + 4 = -5
my _ array [5] = 100 ptr + 5 = 100
✆✌
The average example is given below.

# include < stdio .h >
2 double getAverage ( int * arr , int size ) ;
int main () {
4 int balance [5] = {200 , 20 , 30 , 40 , 50};
double avg ;
6 avg = getAverage ( balance , 5 ) ;
printf ( " Average value is : % f \ n " , avg ) ;
8 return 0;
}
10

double getAverage ( int * arr , int size ) {


12 int i , sum = 0;
double avg ;
14 for ( i = 0; i < size ; ++ i ) {
sum += arr [ i ];
16 }
avg = ( double ) sum / size ;
18 return avg ;
}
✆✌

Average value is : 68.000000
✆✌
A function should never return a pointer to a local variable, even when the compiler
not complains. When declaring an array as variable of the function without size, it is
equivalent to declared pointer. Often this is done to emphasize the fact that the pointer
will be used in a manner equivalent to an array. In the following example

1 # include < stdio .h >

3 void main ( void ) {


char str_arr [ ] = " This is string array . " ;
5 char * str = " This is string pointer . " ;
int i = 0;
7 while ( i < 10) {
printf ( " % s \ t \ t % s \ n " , str_arr ++ , str ++) ;
9 i ++;
}
2.2. POINTER 289

11 return 0;
}
✆✌
Increment and decrement operation is not allowed in arrays while pointers accepts incre-
ment or decrement operations. It is because ‘str arr’ is a fixed address variable. A pointer
can points to the address of specific index element. It can be done like

char s [ ]={ ’a ’ , ’b ’ , ’c ’ , ’d ’ };
2 /* char a is at index 0. *
* char b is at index 1. *
4 * char c is at index 2. *
* char d is at index 3. */
6 p = & s [3]; /* Pointer grabs the address of *
*3 rd index element of array s */
✆✌
Note that pointers assigns address among them. For example, if ‘p’ and ‘q’ are pointer
variables, and ‘q’ points to the memory address 0×04, then ‘p=q’, pointer ‘p’ shall points
to the same address, i.e. to memory address 0×04. See the complete example, that is
given below:

1 # include < stdio .h >

3 int main ( void ) {


char s [ ] = { ’a ’ , ’ b ’ , ’c ’ , ’d ’ , ’e ’ , ’\ n ’ , ’c ’ , ’ \0 ’ };
5 char * p , *q , * r ;
p = & s [3]; /* Pointer grabs the address of *
7 *3 rd index element of array s */
q = p ; /* address assignment from p to q */
9 r = s ; /* address assignment from s to r */
printf ( " Pointer p points to % c \ n " , * p ) ;
11 printf ( " Pointer q points to % c \ n " , * q ) ;
printf ( " Pointer r points to % c \ n " , * r ) ;
13 return 0;
}
✆✌

Pointer p points to d
Pointer q points to d
Pointer r points to a
✆✌

Pointers to Multidimensional Arrays


A two dimensional array may be declared be normal array method or by pointer method.
A two dimensional array by pointer method is declared as shown in the following syntax.

1 int (* mArr ) [2];
✆✌
Here, ‘mArr’ is a pointer-to-array of two columns. Parentheses are used to make prece-
dence of pointer symbol (*) higher than the square bracket operator ([ ]). Square bracket
operator ([ ]) has a higher precedence than dereferencing operator (*). Therefore, a
declaration such as
290 Array & Pointer


1 int * mArr [2];
✆✌
is invalid. An example, in which two dimensional array by pointer method is initialized
and its elements are printed in output console.

1 # include < stdio .h >

3 int main ( void ) {


int * mPtr [ ][3] = {
5 { -1 , 2 , 3} ,
{4 , -3 , 5} ,
7 {5 , 6 , -5}
};
9 // int * mPtr [3] = {1 , 2 , 3};
int i , j ;
11 for ( i = 0; i < 3; i ++) {
for ( j = 0; j < 3; j ++) {
13 printf ( " %2 d \ t " , *(* mPtr + (3 * i ) + j ) ) ;
}
15 printf ( " \ n " ) ;
}
17 return 0;
}
✆✌

-1 2 3
4 -3 5
5 6 -5
✆✌

Pointers as Function Argument


Sometime it may be an requirement to invoke a function with an argument that is itself
a pointer. A function with a pointer is assigned as

1 int sum ( int * arr ) ; // Valid prototype
int sum ( int *) ; // Valid prototype
✆✌
sum() gets the address of the first element of the array, and it learns that it will find an
integer at that location. This prototype function does not tell the size of array. The more
flexible approach of the function is

int sum ( int * arr , int n ) ;
✆✌
Here ‘arr’ is a pointer to the first element of array and ‘n’ is size of the array. In many
instances, the variable is itself a parameter for the current function and may be a pointer to
some type of structure. The ampersand character (&) is not needed in this circumstance
to obtain a pointer value, as the variable is itself a pointer.

1 # include < stdio .h >
2.2. POINTER 291

double getAverage ( int * arr , int size ) ;


3 int main () {
int balance [5] = {200 , 20 , 30 , 40 , 50};
5 double avg ;
avg = getAverage ( balance , 5) ;
7 printf ( " Average value is : % f \ n " , avg ) ;
/* Size of the balance in bytes . */
9 printf ( " The size of balance is % zd bytes .\ n " , sizeof balance ) ;
return 0;
11 }

13 double getAverage ( int * arr , int size ) {


int i , sum = 0;
15 double avg ;
for ( i = 0; i < size ; ++ i ) {
17 sum += arr [ i ];
}
19 avg = ( double ) sum / size ;
/* array ’ arr ’ is not as long as balance , because *
21 * it is not array itself . It represents to the *
* position of first bytes of the array ‘ balance ’. */
23 printf ( " The size of arr is % zd bytes .\ n " , sizeof arr ) ;
return avg ;
25 }
✆✌

The size of arr is 4 bytes .
Average value is : 68.000000
The size of balance is 20 bytes .
✆✌
Consider another piece of code as given below. In this example, enum data type is used
to define index position of rainbow colors by color name. For example, ‘red’ is at index
position ‘0’, ‘orange’ for index ‘1’ and so on. These index values of rainbow colors are
accessed by ‘colour’ variable in for () loop as well as these index values are used to get
the color name from ‘rainbow’ array.

1 # include < stdio .h >

3 enum spectrum {
red , orange , yellow , green , blue , indigo , violet
5 } colour ;

7 char * rainbow [ ] = { " red " , " orange " , " yellow " , " green " ,
" blue " , " indigo " , " violet " };
9

int main () {
11 for ( colour = red ; colour <= violet ; colour ++) {
printf ( " % s " , rainbow [ colour ]) ;
13 }
printf ( " \ n " ) ;
15 return 0;
292 Array & Pointer

}
✆✌

red orange yellow green blue indigo violet
✆✌
In following example pointers are used simply for swapping of two integers of variables
from each other. Integer type variables are pointers by default. Hence, to pass the values,
assigned to integer type variable, to a function, ‘&’ symbol is prefixed to the variables to
pass the address of the variable value stored in the memory.

1 # include < stdio .h >
void swap ( int *x , int * y ) ;
3

int main () {
5 int a = 2 , b = 3;
printf ( " Swapping of values of a and b .\ n " ) ;
7 printf ( " Value of a is % d and value of b is % d .\ n " , a , b ) ;
swap (& a , & b ) ;
9 printf ( " Value of a is % d and value of b is % d .\ n " , a , b ) ;
return 0;
11 }

13 void swap ( int *x , int * y ) {


int t = * x ;
15 *x = *y;
*y = t;
17 return ;
}
✆✌

Swapping of values of a and b .
Value of a is 2 and value of b is 3.
Value of a is 3 and value of b is 2.
✆✌
In the definition of swap() function inside the main function, variables ‘a’ and ‘b’ are used
as addresses. In prototype they are declared as pointers. Because ‘a’ and ‘b’ are integers
so, ‘x’ and ‘y’ are pointers to integers. Hence the prototype function is declare as

1 void swap ( int *x , int * y )
✆✌
Above example is rewritten as shown below. This modified example does not swap the
values of integer variables ‘a’ and ‘b’. On passing of values ‘a’ and ‘b’ to swap() function,
local variable ‘a’ becomes 2 and ‘x’ becomes 3. Again ‘y’ becomes 2. In this swapping,
there is no change in the value of ‘b’. This is why, there is no swapping of values between
variables ‘a’ and ‘b’.

1 # include < stdio .h >

3 void swap ( int x , int y ) ;


int main () {
5 int a = 2 , b = 3;
2.2. POINTER 293

printf ( " Swapping of values of a and b \ n " ) ;


7 printf ( " Value of a is % d and value of is % d .\ n " , a , b ) ;
swap ( a , b ) ;
9 printf ( " Value of a is % d and value of is % d .\ n " , a , b ) ;
return 0;
11 }

13 void swap ( int x , int y ) {


int a = x ;
15 x = y;
y = a;
17 return ;
}
✆✌

Swapping of values of a and b
Value of a is 2 and value of is 3.
Value of a is 2 and value of is 3.
✆✌
In function call by passing the address of a variable is also possible. The function accepts
a pointer and modified the value at the address of this pointer. Local variable is passed
as address to the function, the value of local variable is modified accordingly.

1 # include < stdio .h >

3 void myFunc ( int * p ) { /* Parameter as pointer to integer */


* p = 30; /* Modify the value at the address of pointer */
5 }

7 int main () {
int i = 20; /* Local variable with value 20 */
9 myFunc (& i ) ; /* Address of local var passed to function */
printf ( " % d " , i ) ; /* Print modified value here . It is 30 now */
11 return 0;
}
✆✌

30
✆✌
A function may also be declared as pointer and it returns the address of pointer variable
being returned by retunrn keyword within its code body. See the following example:

1 # include < stdio .h >

3 /* Function shall return address *


* of data it has manipulated . *
5 * Catch the address of myStr *
* where it is stored in memory . */
7 char * myF ( char * ch ) {
/* return the address that was *
9 * caught by function through *
* its arguments char * ch */
294 Array & Pointer

11 return ch ;
}
13

/* Function shall return address of that *


15 * data , which it has manipulated . Catch *
* address of myStr , stored in memory . */
17 char * myF2 ( char * ch ) {
/* Get string through the address *
19 * caught through argument and *
* manipulate string in memory . */
21 ch [5]= ’X ’; /* change alphabet F - > X *
* using index method . */
23

ch ++; /* Increase address by one *


25 * Now , it points to ‘B ’ */

27 /* return the address that was *


* catched by function through *
29 * its arguments char * ch */
return ch ;
31 }

33 int main () {
/* Declare a pointer and assign string to it .*
35 * Memory allocated internally as declaration *
* and initializati on takes simultaneou sl y . *
37 * In case of later assignment , first create *
* memory using malloc () then copy string . */
39 char * myStr = " A B C D E F G H I J K L M N O P Q R S T U V W X Y Z" ;
// OR
41 // char myStr [27] = " A B C D E F G H I J K L M N O P Q R S T U V W X Y Z";

43 /* string variables or string pointers *


* acts as their addresses . This is why *
45 * * myStr shows error as we are trying *
* to convert address ( numeric value ) *
47 * into pointers . */
printf ( " %26 s \ n " , myF ( myStr ) ) ;
49 printf ( " %26 s \ n " , myF2 ( myStr ) ) ;
return 0;
51 }
✆✌

ABCDEFGHIJKLMNOPQRSTUVWXYZ
BCDEXGHIJKLMNOPQRSTUVWXYZ
✆✌

Address as Function Argument


We can pass an address to a function as its argument. The value of the variable at
its address is extracted in the function. This value is used in the expressions or the
2.2. POINTER 295

statements in function body. In example given below, integer variable ‘i’ is scanned as
integer and stored in the memory address. Address of this variable is passed to function
‘ZeroCumSum’. In the function, value of the address is extracted by dereference and used
in the cumulative sum expressions.

# include < stdio .h >
2 /* Catch address through function argument . */
int ZeroCumSum ( int * i ) {
4 int sum =0;
/* Do what algorithm said . */
6 while (* i > 0) {
sum += * i ;
8 (* i ) - -;
}
10 /* Return result . */
return sum ;
12 }

14 int main () {
/* Initialize the variables . */
16 int i , csum ;
/* Enter a number . */
18 printf ( " Enter a number : " ) ;
scanf ( " % d " , & i ) ;
20 /* Get cumulative sum . Here , *
* i is passed to function as *
22 * as an address argument . */
csum = ZeroCumSum (& i ) ;
24 /* Print output . */
printf ( " Cumsum is % d \ n " , csum ) ;
26 return 0;
}
✆✌

Enter a number : 10
Cumsum is 55
✆✌
The parameter data type of argument in a function must be same as the data type whose
addresses is being passed to the function.

# include < stdio .h >
2 # include < string .h >

4 /* Parameter is flaot type , same as *


* datatype whose address is passed . */
6 void outv ( float * f ) {
printf ( " % f \ n " , * f ) ;
8 return ;
}
10

int main () {
12 /* Float data type variable */
296 Array & Pointer

float f =12.5;
14 /* Address of float type variable */
outv (& f ) ;
16 return 0;
}
✆✌

12.5
✆✌
Another example with double data type variable.

1 # include < stdio .h >
# include < string .h >
3

/* Parameter is flaot type , same as *


5 * datatype whose address is passed . */
void outv ( double * f ) {
7 printf ( " % lf \ n " , * f ) ;
return ;
9 }

11 int main () {
/* Float data type variable */
13 double f =12.5;
/* Address of double type variable */
15 outv (& f ) ;
return 0;
17 }
✆✌

12.5
✆✌
Passing of address of the structures as function parameter is explained in the following
example.

1 # include < stdio .h >
# include < string .h >
3

struct s {
5 double d ;
};
7

/* Parameter is struct type , same as *


9 * datatype whose address is passed . */
void outv ( struct s * f ) {
11 printf ( " % lf \ n " , f - > d ) ;
return ;
13 }

15 int main () {
/* Structure variable */
17 struct s myS ;
2.2. POINTER 297

myS . d = 11.5; // Assignment


19 /* Pass address of structure */
outv (& myS ) ;
21 return 0;
}
✆✌

11.500000
✆✌

Pointer Equivalent to Array


A pointer type **p is also represents to an array type arr [ ][ ]. Here [ ][ ] represents to
dynamic size of array in two dimensions. Here first asterisk in **p represents to number
of the rows while second asterisk represents to dynamic size of each row. It should be
remember that, the dynamic length should that dimension which is used to store new
data. For example, in two dimensional matrix, column length is fixed and row length is
dynamic. So,

1 /* Fixed col ( k ) length and variable row length */
int myA [ ][ k ];
✆✌
represents to a two dimensional matrix with fixed length of columns and variable length
of rows. Arrays declared with variable size returns compile time error if they are not
initialized.

# include < stdio .h >
2

int main () {
4 int mat [][3]; /* variable row declaration . */
return 0;
6 }
✆✌
Above example shall return compile time error as the array is not fixed or initialized.
Now above code is modified as shown in the following example.

# include < stdio .h >
2

int main () {
4 /* Array with variable rows declared & initialized . */
int mat [ ][3]={};
6 int myA [2][3]; /* fixed size declaration . */
return 0;
8 }
✆✌
Now, above example will compile without showing any error. Again, in three dimensional
array, rows and columns are fixed in length while layer length (z-axis) is dynamic. So, a
three dimensional array is represented as

/* Fixed row ( x ) & col ( y ) and variable layers */
2 int myA [ ][ x ][ y ];
✆✌
298 Array & Pointer

A two dimensional array having ‘m’ rows and ‘n’ columns is equivalent to pointer as
shown in the syntax given below:

arr [ m ][ n ] = *(*( p + m ) + n )
✆✌
Two dimensional array can be pointed by a pointer variable. Value at the address pointing
to an element of the array can be obtain by de-reference. The two dimensional reference
is done as shown in the table below.

Pointer Equals Array


*(*(p + 0) + 0) *(*(p)) p[0][0]
*(*(p + 0) + 1) *(*(p) + 1) p[0][1]
*(*(p + 1) + 0) *(*(p + 1)) p[1][0]
*(*(p + 1) + 1) *(*(p + 1) + 1) p[1][1]
*(*(*(p + 0) + 0) + 2) *( **p + 2 ) p[0][0][2]
*(*(*(p + 0) + 1) + 0) **(*p + 1 ) p[0][1][0]
*(*(*(p + 0) + 0) + 0) ***p p[0][0][0]

Table 2.1: Pointer and its equivalent to array.

The pointer of a multi-dimensional matrix has meaning like



1 ...*(*( ptr + i ) + j ) ....
✆✌
Here, i is row number and j is column number, all started from zero to continue.

*(*(p)) *(*(p)+1)
c1 c2
r1 10 0 0 0 20 0 0 0

r2 15 0 0 0 2 0 0 0

*(*(p+1)) *(*(p+1)+1)


1 # include < stdio .h >

3 int main () {
int mat [3][3] = {
5 {11 , 24 , 53} ,
{45 , 45 , 64} ,
7 {77 , 87 , 99}
2.2. POINTER 299

};
9 printf ( " mat [0][0] element is = % d \ n " ,*(*( mat +0) +0) ) ;
printf ( " mat [0][2] element is = % d \ n " ,*(*( mat +0) +2) ) ;
11 return 0;
}
✆✌

mat [0][0] element is = 11
mat [0][2] element is = 53
✆✌
Similarly, a three dimensional matrix has meaning like

...*(*(*( ptr + k ) + i ) + j ) ....
✆✌
Here, i is row number and j is column number and k is layer number, all started from
zero to continue.

1 # include < stdio .h >

3 int main () {
int mat [ ][2][3] = {
5 {
{11 , 24 , 53} ,
7 {45 , 45 , 64}
},
9 {
{1 , 2 , 3} ,
11 {5 , 4 , 6}
}
13 };
/* First layer , first row first element */
15 printf ( " mat [0][0][0] element is = % d \ n " ,*(*(*( mat +0) +0) +0) ) ;
/* Second layer , second row first element */
17 printf ( " mat [1][1][0] element is = % d \ n " ,*(*(*( mat +1) +1) +0) ) ;
return 0;
19 }
✆✌

mat [0][0][0] element is = 11
mat [1][1][0] element is = 5
✆✌
In the following example, a matrix array is passed to a array ‘ar’ of pointers to an integer
and this array pointer is used to access the elements of the matrix.

# include < stdio .h >
2

int main () {
4 int mat [3][3] = {
{11 , 24 , 53} ,
6 {45 , 45 , 64} ,
{77 , 87 , 99}
8 };
300 Array & Pointer

int (* a ) [3];
10 ar = mat ;
printf ( " ar [2][2] element is = % d \ n " , *(*( ar +2) +2) ) ;
12 printf ( " ar [0][2] element is = % d \ n " , *(*( ar +0) +2) ) ;
return 0;
14 }
✆✌

mat [2][2] element is = 99
mat [0][2] element is = 53
✆✌

# include < stdio .h >
2

int main () {
4 int Arr [3][3] = {
{1 , 2 , 3} ,
6 {4 , 5 , 6} ,
{7 , 8 , 9}
8 };
int (* mat ) [3];
10 mat = Arr ;
printf ( " Element at mat [0][1] = % d \ n " , *(*( mat +0) +1) ) ;
12 printf ( " 8 th element from positino of mat [0][0] = % d \ n " ,
(*( mat + 0) ) [8]) ;
14 printf ( " 6 th element from position of mat [0][2] = % d \ n " ,
(*( mat + 0) + 2) [6]) ;
16 return 0;
}
✆✌

Element at mat [0][1] = 2
8 th element from the position of mat [0][0] = 9
6 th element from the position of mat [0][2] = 9
✆✌
Following is an example in which a 3D matrix is accessed by using a pointer.

1 # include < stdio .h >

3 int main () {
int Arr [3][3][3] = {
5 { /* [ x ][ y ] matrix with [ z =0] */
{11 , 12 , 13} ,
7 {14 , 15 , 16} ,
{17 , 18 , 19}
9 },
{ /* [ x ][ y ] matrix with [ z =1] */
11 {21 , 22 , 23} ,
{24 , 25 , 26} ,
13 {27 , 28 , 29}
},
15 { /* [ x ][ y ] matrix with [ z =2] */
2.2. POINTER 301

{31 , 32 , 33} ,
17 {34 , 35 , 36} ,
{37 , 38 , 39}
19 }
};
21 int (* mat ) [3][3];
mat = Arr ;
23 printf ( " Element at mat [0][1][1] = % d \ n " ,
*(*(*( mat + 0) + 1) + 1) ) ;
25 printf ( " 8 th element from position of mat [0][2][0] = % d \ n " ,
(*(*( mat + 0) + 2) ) [8]) ;
27 printf ( " 8 th element from position of mat [0][2][0] = % d \ n " ,
(*( mat + 0) ) [2][8]) ;
29 return 0;
}
✆✌

Element at mat [0][1][1] = 15
8 th element from the position of mat [0][2][0] = 26
8 th element from the position of mat [0][2][0] = 26
✆✌

2.2.3 Pointers and Text Strings


Historically, text strings in C have been implemented as array of characters, with the
last byte in the string being a character code zero, or the null character ‘\0’. Most
C implementations came with a standard library of functions for manipulating strings.
Many of the more commonly used functions expect the strings to be null terminated string
of characters. To use these functions requires the inclusion of the standard C header file
“string.h”. A statically declared, initialized string would look similar to the following:

1 static const char * myFormat = " Total Amount Due : % d " ;
✆✌
The variable ‘myFormat’ can be view as an array of 21 characters. There is an implied
null character (’\0’) tacked on to the end of the string after the ’d’ as the 21st item in
the array. You can also initialize the individual characters of the array as follows:

1 static const char myFlower [ ]
= { ’P ’ , ’e ’ , ’t ’ , ’u ’ , ’n ’ , ’i ’ , ’a ’ , ’ \0 ’ };
✆✌
An initialized array of strings would typically be done as follows:

static const char * myColors [ ] = { " Red " , " Green " , " Blue " };
✆✌
The initialization of an especially long string can be splitted across lines of source code
as follows.

1 static char * longString = " My name is XYZ . " ;
✆✌
The library functions those are used with strings are discussed in later. A simple example
of copying string from one variable to other by using pointer is given below.
302 Array & Pointer


1 # include < stdio .h >
/* Defined two arrays to be copied */
3 char A [80] = " Lucknow is capital city . " ;
char B [80];
5

int main ( void ) {


7 /* First pointer A */
char * ptrA ;
9 /* Second pointer B */
char * ptrB ;
11 /* Assign string pointer of *
* array A to pointer ptrA */
13 ptrA = A ;
/* Assign string pointer of *
15 * array B to pointer ptrB */
ptrB = B ;
17 /* do loop */
while (* ptrA != ’ \0 ’) {
19 /* Copy text from array A to array *
* B using pointers prtA and ptrB */
21 * ptrB ++ = * ptrA ++;
}
23 /* Add line terminating value */
* ptrB = ’ \0 ’;
25 /* Show array B on screen */
puts ( B ) ;
27 return 0;
}
✆✌
From above example, always remember that a pointer to an array always points to the
elements of the array and make copy-paste an element from one array to another array.
Pointer never stores elements itself. The output of the above example is given below:

Lucknow is capital city .
✆✌
By default, strings are pointer to itself. For example “I am a king” is a pointer to
itself. This pointer points to the first character “I”. See example

1 # include < stdio .h >

3 int main ( int argc , char * argv [ ]) {


int i =0;
5 for ( i =0;*( " I am king " + i ) != ’ \0 ’ ; i ++)
printf ( " % c \ n " ,*( " I am king " + i ) ) ;
7 return 0;
}
✆✌
In above example

*( " I am king " + i )
✆✌
2.2. POINTER 303

extracts character by character from the string pointed by string itself. for loop is used to
print all characters. When string pointer encountered by a null character, loop is halted.
Output of above example is

I

a
m

k
i
n
g
✆✌

Pointers to Function
To declare a pointer-to-function do:

1 int (* pf ) () ;
✆✌
The question rises why this declaration is not written as

1 int * pf () ;
✆✌
The reason is that parentheses operator, ( ), has higher precedence than that of derefer-
encing operator (*). Hence for pointer-to-function variable, dereferencing of function is
grouped by parentheses. Example for pointer-to-function is given below.

1 # include < stdio .h >

3 int main () {
int (* r ) () ;
5 r = puts ;
(* r ) ( " My String " ) ;
7 return 0;
}
✆✌
Here, the function line is equivalent to

puts ( " My String " ) ;
✆✌

My String
✆✌
Unlike the normal pointers, a function pointer points to code, not data. A function
pointer points to the memory address where execution codes are stored. Remember that,
we do not allocate or de-allocate memory using function pointers.

1 # include < stdio .h >
304 Array & Pointer

3 void myFunc ( int a ) {


printf ( " Value of a is % d \ n " , a ) ;
5 }

7 int main () {
void (* ptrFunc ) ( int ) = & myFunc ;
9 (* ptrFunc ) (10) ;
return 0;
11 }
✆✌

Value of a is 10
✆✌
Function name is also points to the address of execution code. Therefore, use of ‘myFunc’
at the place of ‘&myFunc’ in the following example give same result as given by above
example.

1 # include < stdio .h >

3 void myFunc ( int a ) {


printf ( " Value of a is % d \ n " , a ) ;
5 }

7 int main () {
void (* ptrFunc ) ( int ) = myFunc ;
9 ptrFunc (10) ;
return 0;
11 }
✆✌

Value of a is 10
✆✌
A pointer-to-function that returns output as string pointer is shown in the following
example:

1 # include < stdlib .h >
# define STRLEN 1024
3

char * str_func ( char * str ) {


5 char * s = NULL ;
/* Allocate the required memory space . */
7 s = malloc ( sizeof ( char ) *( STRLEN + 1) ) ;
/* Copy contents of str into memory */
9 memcpy (s , str , STRLEN ) ;
/* Return the pointer of memory location */
11 return s ;
}
13

main ( int argc , char * argvc [ ]) {


15 /* Test string . */
char s [ STRLEN ] = " The Sarnath . " ;
17 /* Returned string pointer . */
2.2. POINTER 305

char * st ;
19 /* Pointer to function declaration . */
int (* fn ) () ;
21 /* Get the function object pointer . */
fn = str_func ;
23 /* Pass the func object to declared function . */
st = (* fn ) ( s ) ;
25 /* Print returned string . */
printf ( " % s \ n " , st ) ;
27 return 0;
}
✆✌

The Sarnath .
✆✌
C also allows to create pointer-to-function. Pointer-to-function can get rather messy.
Declaring a data type to a function pointer generally clarifies the code. Here’s an example
that uses a function pointer, and a (void *) pointer to implement what’s known as a
callback. A switch case example

1 # include < stdio .h >
int add ( int a , int b);
3 int sub ( int a , int b);
int mul ( int a , int b);
5 int div ( int a , int b);

7 int main () {
int i , result ;
9 int a = 10;
int b = 5;
11 printf ( " Enter the value between [0 , 3] : " ) ;
scanf ( " % d " , & i ) ;
13 switch ( i ) {
case 0:
15 result = add (a , b ) ;
break ;
17 case 1:
result = sub (a , b ) ;
19 break ;
case 2:
21 result = mul (a , b ) ;
break ;
23 case 3:
result = div (a , b ) ;
25 break ;
}
27 printf ( " : - > Result is % d " , result ) ;
return 0;
29 }

31 int add ( int i , int j ) {


return ( i + j ) ;
306 Array & Pointer

33 }

35 int sub ( int i , int j ) {


return ( i - j ) ;
37 }

39 int mul ( int i , int j ) {


return ( i * j ) ;
41 }

43 int div ( int i , int j ) {


return ( i / j ) ;
45 }
✆✌

Enter the value between 0 and 3 : 2
: - > Result is 50
✆✌
Array of function pointers may also be used to access a function by using array pointer
index. See the example given below:

# include < stdio .h >
2 # include < math .h >
typedef int *(* func ) ( int ) ;
4

int mySum ( int i ) {


6 return ( i + 2) ;
}
8

int mySub ( int i ) {


10 return ( i - 2) ;
}
12

int main () {
14 func myFuncArray [10] = { NULL };
myFuncArray [0] = & mySum ;
16 myFuncArray [1] = & mySub ;
printf ( " % d \ n " , (* myFuncArray [0]) (5) ) ;
18 printf ( " % d \ n " , (* myFuncArray [1]) (5) ) ;
return 0;
20 }
✆✌

7
3
✆✌
In above example, a array function pointer is created by using typedef and each array
function pointer is assigned the address of the function object.

typedef int *(* func ) ( int ) ; // array function pointer
2 myFuncArray [0] = & mySum ; /* assigning function pointer *
* to array function pointer . */
✆✌
2.2. POINTER 307

When array function pointer is called, we get desired result. Above array function pointer
is re-implemented in the following example.

1 # include < stdio .h >
int add ( int a , int b ) ;
3 int sub ( int a , int b ) ;
int mul ( int a , int b ) ;
5 int div ( int a , int b ) ;
/* Function pointer used for execution of *
7 * four functions called by their positions . */
int (* operator [4]) ( int a , int b ) = { add , sub , mul , div };
9

int main () {
11 int i , result ;
int a = 10;
13 int b = 5;
printf ( " Enter the value between [0 , 3] : " ) ;
15 scanf ( " % d " , & i ) ;
result = operator [ i ]( a , b ) ;
17 printf ( " : - > Result is % d " , result ) ;
return 0;
19 }

21 int add ( int i , int j ) {


return ( i + j ) ;
23 }

25 int sub ( int i , int j ) {


return ( i - j ) ;
27 }

29 int mul ( int i , int j ) {


return ( i * j ) ;
31 }

33 int div ( int i , int j ) {


return ( i / j ) ;
35 }
✆✌

Enter the value between 0 and 3 : 1
: - > Result is 5
✆✌
A struct member function can also be created by using pointer. Following is the example
for the purpose.

# include < stdio .h >
2 # include < string .h >
/* Global declaration of file pointer . */
4 FILE * fp ;

6 data type struct {


308 Array & Pointer

int (* open ) ( void ) ;


8 int (* del ) ( void ) ;
} file ;
10

int my_file_open ( void ) {


12 fp = fopen ( " my_file . txt " , " w " ) ;
if ( fp == NULL ) {
14 printf ( " File can not be opened .\ n " ) ;
} else {
16 printf ( " File opened .\ n " ) ;
fputs ( " Hello World ! " , fp ) ;
18 }
}
20

void my_file_del ( void ) {


22 printf ( " Try to remove .\ n " ) ;
if ( remove ( " my_file . txt " ) == 0) {
24 printf ( " File is removed .\ n " ) ;
} else {
26 printf ( " No file to remove .\ n " ) ;
}
28 }

30 file create ( void ) {


file my_file ;
32 my_file . open = my_file_open ;
my_file . del = my_file_del ;
34 my_file . open () ;
my_file . del () ;
36 return my_file ;
}
38

int main ( int argc , char * argv [ ]) {


40 create () ;
return 0;
42 }
✆✌

Casting of Pointer
To assign an integer type pointer ‘iptr’ to a floating type pointer ‘fptr’, we cast ‘iptr’ as
a floating type pointer and then carry out the assignment, as shown :

fptr = ( float *) iptr ;
✆✌
When a pointer is casted from old data type to new data type then it only keeps the
address of a size of new data type. For example, in Linux GCC, data size of integer is 4
byte while data size of character is 1 byte. Hence when integer data type is casted into
character data type and pointed by a pointer then pointer keep the address one byte at
time.
2.2. POINTER 309


1 # include < stdio .h >

3 int main () {
int a = 320;
5 /* Integer 320 = binary 00000001 01000000 */
char * ptr ;
7 ptr = ( char *) & a ;
/* Cast intger into character and point to first *
9 * byte of the integer containing value 01000000 */

11 printf ( " % d " , * ptr ) ; /* Print 01000000 as decimal 64 */


return 0;
13 }
✆✌

64
✆✌

Address Copying Vs Content Copying


A pointer points to location of content stored in the memory. It does not point to value
stored in the memory. For example, take a string “This”, that is stored in memory
location 0×001250. Now this value is assigned to a pointer variable (say ‘str’) then pointer
holds address value 0×001250 not to the value “This”. When one pointer is assigned to
the other pointer then only location of contents is assigned. See the example:

1 # include < stdio .h >

3 int main () {
char * str = " This " ; /* location at 0 x0011 ( say ) */
5 char * pt = " That " ; /* location at 0 x0022 ( say ) */
printf ( " str :% s , pt :% s \ n " , str , pt ) ;
7 str = pt ; /* str ’s memory location changed to 0 x0022 */
printf ( " str :% s \ n " , str ) ;
9 return 0;
}
✆✌

str : This , pt : That
str : That
✆✌
Here, address of ‘pt’ is copied to address of ‘str’. If we wants to copy contents from the
memory location pointed by ‘pt’ to the memory location pointed by pointer ‘str’, then
strcpy function is used.

# include < stdio .h >
2 # include < string .h >

4 int main () {
char * str = " This " ; /* location at 0 x0011 ( say ) */
6 char * pt = " That " ; /* location at 0 x0022 ( say ) */
310 Array & Pointer

printf ( " str :% s , pt :% s \ n " , str , pt ) ;


8 str = malloc (5) ; /* Memory allocation is required as *
* compiler do not kew the memory size *
10 * assigned to str pointer while copy . */
strcpy ( str , pt ) ; /* contents of memory location of ’ pt ’ *
12 * is copied at memory location of ’ str ’ */
printf ( " str :% s \ n " , str ) ;
14 free ( str ) ;
return 0;
16 }
✆✌

str : This , pt : That
str : That
✆✌
Here, contents from the memory location pointed by pointer ‘pt’ are copied into the
memory location pointed by pointer ‘str’.

2.2.4 Dangling & Wild Pointers


Dangling pointers and wild pointers are pointers that do not point to a valid object of the
appropriate type. Dangling pointers arise when it points to the location that is deallocated
without modifying the value of the pointer. The pointer still points to the memory
location of the deallocated memory. Dangling pointers causes memory sharing violation
and returns error of segmentation faults in UNIX and Linux, or general protection faults
in Windows.

# include < stdio .h >
2

int main () {
4 {
char * dp = NULL ;
6 {
char c ;
8 dp = & c ;
printf ( " % d \ n " , dp ) ;
10 }
/* dp is now a dangling pointer */
12 }

14 return 0;
}
✆✌

2280807
✆✌
Another example of dangling pointer, in which function ‘func’ returns the addresses of a
stack-allocated local variable. Once called function returns, the space for these variables
gets deallocated and technically they have “garbage values”.
2.2. POINTER 311


1 # include < stdio .h >

3 int * func ( void ) {


int num = 1234;
5 return & num ;
}
7

int main () {
9 printf ( " % d \ n " , func () ) ;
printf ( " % d \ n " , * func () ) ;
11 return 0;
}
✆✌

2280756
2280756
✆✌
Wild pointers arise when a pointer is used prior to initialization to some known state,
which is possible in some programming languages. They show the same erratic behavior
as dangling pointers, though they are less likely to stay undetected because many com-
pilers will raise a warning at compile time if declared variables are accessed before being
initialized.

# include < stdio .h >
2

int main () {
4 int i ; // Declared but not initialized
printf ( " % d \ n " , i ) ; // i acts as wild pointer
6 return 0;
}
✆✌
Output is strange:

1629773328
✆✌

2.2.5 Pointer, Variable & Address


A variable is a literal name which addresses to a memory location. An address is a
reference to a variable. Pointer points to the address of a variable. One of the most
common problem arises in C programming is analyses of pointer variable size, position
of its current address and next address after arithmetic operations. The pointers and
their locations are similar to milestones along the road. Suppose, a road along-with the
distance milestone separated by one meter (for concept purpose).
312 Array & Pointer

2 3
4
1
10
5
9
6 8
7
0

Initially, we are at the 3rd milestone. One meter long unit is used to measure the
distances between two consecutive milestones. In one step measurement, next milestone
will be 4th one. It means that, if initially pointer location is at 3rd milestone then after
one increment (by one meter), the pointer location will be at 4th milestone.

2 3
bc
b 4
1
10
5
9
6 8
7
0

Now, we change measurement count from one meter long unit to two meter long unit.
Assume that initially location pointer is at 3rd milestone. In one increment to the location
pointer (two meter unit), next milestone will be 5th one.

2 bc 3
4
1
10
5b
9
6 8
7
0

In C programming, integer type variable is four byte long. So, if initially pointer
location of the integer variable is at 3rd milestone then after one increment (by four
bytes) to the integer variable, the pointer location shall be at 7th milestone.

2 bc 3
4
1
10
5
9
6 8
7b
0

In the following example a character data-type pointer is declared as variable ‘a’.


Pointer arithmetic is performed. New locations of pointers fetched to see the change in
the length between two consecutive addresses of pointer.
2.2. POINTER 313


1 # include < stdio .h >

3 int main () {
char * a ;
5 printf ( " % p \ n " , a ) ;
a ++; /* First increment of pointer */
7 printf ( " % p \ n " , a ) ;
a ++; /* Second increment of pointer */
9 printf ( " % p \ n " , a ) ;
return 0;
11 }
✆✌

0 xb 7758000 % First address location of character
% pointer is here
0 xb 7758001 % New location of character pointer after
% first increment . Distance from the
% first address location is 1 bytes .
0 xb 7758002 % New location of character pointer after
% second increments . Distance from the
% first address location is 2 bytes .
✆✌

Bytes Memory Blocks Memory Address

Byte No. 8 0×b7758008


Byte No. 7 0×b7758007
Byte No. 6 0×b7758006
Byte No. 5 0×b7758005
Byte No. 4 0×b7758004
Byte No. 3 0×b7758003
Byte No. 2 a+2 0×b7758002
Byte No. 1 a+1 0×b7758001
Byte No. 0 a 0×b7758000

In the following example an integer data-type pointer is declared as variable ‘a’. Pointer
arithmetic is performed. New locations of pointers fetched to see the change in the length
between two consecutive addresses of pointer.

# include < stdio .h >
2

int main () {
4 int * a ;
printf ( " % p \ n " , a ) ;
6 a ++; /* First increment of pointer */
printf ( " % p \ n " , a ) ;
8 a ++; /* Second increment of pointer */
printf ( " % p \ n " , a ) ;
314 Array & Pointer

10 return 0;
}
✆✌

0 xb 7758000 % First address location of integer pointer is here
0 xb 7758004 % New location of integer pointer after first increment .
% Distance from the first address location is 4 bytes .
0 xb 7758008 % New location of integer pointer after second increments .
% Distance from the first address location is 8 bytes .
✆✌

Bytes Memory Blocks Memory Address

Byte No. 8 a+2 0×b7758008


Byte No. 7 0×b7758007
Byte No. 6 0×b7758006
Byte No. 5 0×b7758005
Byte No. 4 a+1 0×b7758004
Byte No. 3 0×b7758003
Byte No. 2 0×b7758002
Byte No. 1 0×b7758001
Byte No. 0 a 0×b7758000

In the following example a two dimensional integer data-type array is declared and initial-
ized as variable ‘a’. Pointer arithmetic is performed. New locations of pointers fetched to
see the change in the length between two consecutive addresses of pointer for first column.

1 # include < stdio .h >

3 int main ( void ) {


int * mPtr [ ][3] = {
5 { -1 , 2 , 3} , /* 8 bytes , 8 bytes , 8 bytes */
{4 , -3 , 5} , /* 8 bytes , 8 bytes , 8 bytes */
7 {5 , 6 , -5} /* 8 bytes , 8 bytes , 8 bytes */
}; /* 3 By 3 matrix */
9 int i , j ;
for ( i = 0; i < 3; i ++) {
11 printf ( " %2 d -> % p \ t " , *(* mPtr + (3 * i ) ) , ( mPtr + (3 * i ) ) ) ;
printf ( " \ n " ) ;
13 }
return 0;
15 }
✆✌

-1 -> 0 xbfa 09 b 8 c % 1 X 1 element is at this address
4 -> 0 xbfa 09 bb 0 % 2 X 1 element is at this address
% Distance from 1 X 1 element is 24 Bytes
5 -> 0 xbfa 09 bd 4 % 3 X 1 element is at this address
% Distance from 1 X 1 element is 48 Bytes
2.2. POINTER 315

% Distance from 2 X 1 element is 24 Bytes


✆✌
In pointers, we must be cautious, that pointers holds address values. The pointers are used
to hold addresses of other memory bytes not the numbers, hence only pointer comparison,
addition and subtraction operations are allowed . For example, in following code lines,
the memory byte pointed by the variable x holds value 20 as binary 10100.

int * x = 20; // assign address
✆✌

∗x
00000000 00000000 00000000 00010100
0×45 0×46 0×47 0×48

When pointer is assigned a value, it is treated as address value. Now, we can retrieve this
address by just calling pointer as

1 printf ( " % d " , x ) ;
✆✌
We shall get value 20 as its result. But when we dereference the variable x as

1 printf ( " % d " , * x ) ;
✆✌
It tries to read the value at address 0×14 (equal to decimal 20 and binary 00010100), it
gives access status violation as we try to access restricted memory space set by the OS.
It is because, dereference is the retrieving of value from that address which is stored in
the memory bytes pointed by the dereferencing pointer. If we change the value of x as

1 int * x = 2346192; // assign address
printf ( " % d " , * x ) ;
✆✌

∗x
00000000 00100011 11001100 11010000
0×45 0×46 0×47 0×48

We get a random value which is stored at address 0×23CCD0 (equal to decimal 2346192 or
binary 1000111100110011010000). Note that, the address location 0×23CCD0 is beyond
the restricted memory region set by OS, hence it returns random output.

2.2.6 Constant Pointers


A pointer may be declared as constant by using const keyword.

int i = 5;
2 const int * p = & i ;
// Or
4 int const * p = & i ;
✆✌
316 Array & Pointer

There are two cases, (i) where a pointer pointed to constant data (pointee) and pointee
can not be changed, and (b) where constant pointer (address) can not be changed. The
usual pointer-pointee relation are given below:

# include < stdio .h >
2 # include < stdlib .h >

4 int main () {
int i = 2;
6 int j = 3;
int * k = & j ; // k points to j and * k is 3
8 printf ( " % d \ n " , * k ) ;
j = 6; // Now both j and * k are 6
10 printf ( " % d % d \ n " , j , * k ) ;
* k = 7; // j and * k are 7. Pointee changes
12 printf ( " % d % d \ n " , j , * k ) ;
k = & i ; // k points to i . * k is 2. Pointer changes
14 printf ( " % d % d \ n " , i , * k ) ;
* k = 8; // i and * k are 8 now . Pointee changes
16 printf ( " % d % d \ n " , i , * k ) ;
return 0;
18 }
✆✌

3
6 6
7 7
2 2
8 8
✆✌
Now the const keyword is used as shown in modified example. There are errors shows by
the compiler.

1 # include < stdio .h >
# include < stdlib .h >
3

int main () {
5 int i = 2;
const int j = 3;
7 const int * k = & j ;
j = 6; // Error ! assignment of read - only variable ’j ’
9 * k = 7; // Error ! assignment of read - only location ’* k ’
k = & i ; // k points to i . * k is 2. Pointer changes
11 * k = 8; // Error ! assignment of read - only location ’* k ’
return 0;
13 }
✆✌
Here, code line

1 // + - - Pointee type , i . e . constant pointee
// |
3 const int * k = & j ;
✆✌
2.2. POINTER 317

&j
0×50 0×51 0×52 0×53 0×54 0×55 0×56

const int *k = &j 2 3 4 5 6 7 8

(const) j j

represents that ‘k’ is a non constant type pointer and the value to which it is pointing
is constant type. Therefore, value of ‘j’ can not be changed while address of ‘k’ can be
changed.

1 # include < stdio .h >
# include < stdlib .h >
3

int main () {
5 int i = 2;
const int j = 3;
7 const int * k = & j ;
// int const * k = & j ; // Or state
9 printf ( " Address of k is % x \ n " , k ) ;
k = & i ; // k points to i . * k is 2. Pointer changes
11 printf ( " New address of k is % x \ n " , k ) ;
//
13 printf ( " i : %d , k : % d \ n " , i , * k ) ;
return 0;
15 }
✆✌

Address of k is 0 x 22 ff 44
New address of k is 0 x 22 ff 48
i : 2, k : 2
✆✌
Similarly, if

1 // + - - Pointer type , i . e . constant pointer
// |
3 int * const k = & j ;
✆✌
then, pointer becomes constant while value of pointee can be changed. Notice the position
of asterisk (*) not the const keyword.
(const) *k

&j
0×50 0×51 0×52 0×53 0×54 0×55 0×56

int * const k = &j 2 3 4 5 6 7 8

j
318 Array & Pointer


1 # include < stdio .h >
# include < stdlib .h >
3

int main () {
5 int i = 2;
int j = 3;
7 int * const k = & j ;
printf ( " Address of k is % d \ n " , k ) ;
9 printf ( " Old values - j : %d , k : % d \ n " , j , * k ) ;
j = 5; // k points to i . * k is 2. Pointer changes
11 printf ( " New values - j : %d , k : % d \ n " , j , * k ) ;
// k = & i ;// Error ! assignment of read - only variable ’k ’
13 return 0;
}
✆✌

Address of k is 0 x 22 ff 44
Old values - j : 3 , k : 3
New values - j : 5 , k : 5
✆✌
The change in the position of the asterisk (*) and keyword const changes the pointer and
pointee type. The general representation is

1 int n = 5;
int * p = & n ; // non - const - Pointer to non - const - Pointee
3 const int * p = & n ; // non - const - Pointer to const - Pointee
int * const p = & n ; // const - Pointer to non - const - Pointee
5 const int * const p = & n ; // const - Pointer to const - Pointee
✆✌
The data type keywords before the asterisk symbol represent the nature of the pointee
(the address location where data is stored). The data type keywords after the asterisk
symobl represent the nature of the pointer itself. This contents add in C just before
Memory Allocation section.

2.2.7 Memory Allocation


There are two types of memory allocation. (i) Static memory allocation and (ii) dynamic
memory allocation. When a static or global variable is declared, it allocates static memory
of one block of space or of a fixed size. The space is allocated once is never freed until
program is not exit. Automatic variables, such as a function argument or a local variable
allocate memory space dynamically. The allocated space is deallcoated (freed) when the
compound statement that contains these variable is exited.

Dynamic Memory Allocation


malloc is used to allocate dynamic memory to a pointer. It returns pointer to newly
allocated memory space block and null pointer if memory allocation failed. This is why,
before using the memory block, the size of the memory block should be checked. The
contents of the block are undefined. It should be initialized manually. The syntax of the
function is given as
2.2. POINTER 319


1 void * malloc ( size_t size ) ;
✆✌
The address of a block returned by malloc or realloc in GNU systems is always a multiple
of eight. Casting of malloc() function is required as shown in the above syntax. The
function, malloc is meant for implementing dynamic memory allocation. It is defined in
stdlib.h or malloc.h, depending on what operating system is used. malloc.h contains only
the definitions for the memory allocation functions and not the rest of the other functions
defined in stdlib.h. It is good programming practices that when allocated memory is no
longer needed, free should be called to release it back to the memory pool. Overwriting
a pointer that points to dynamically allocated memory can result in that data becoming
inaccessible. If this happens frequently, eventually the operating system will no longer
be able to allocate more memory for the process. Once the process exits, the operating
system is able to free all dynamically allocated memory associated with the process. A
simple example is

1 # include < stdio .h >

3 int main ( void ) {


int * MemAllo ;
5 /* Allocate the memory space */
MemAllo = ( char *) malloc (100) ;
7 if ( MemAllo ) {
printf ( " Memory allocation successfull !!\ n " ) ;
9 } else {
printf ( " Memory allocation un - successfull !! " ) ;
11 exit (0) ;
}
13 /* Allocated memory is not freed here .*
* It is not C programming standards . */
15 return 0;
}
✆✌

Memory allocation successfull !!!!!
✆✌
In standard C programming, each allocated memory should be freed when it is not in use.
Unfreed memory is locked by the allocating program and can not be accessed by other
programs until the program which allocates memory space is not terminated. free() is
used to free the allocated memory.

1 # include < stdio .h >

3 int main ( void ) {


int * p ;
5 /* Allocate space for 3490 integers ! */
p = malloc ( sizeof ( int ) * 3490) ;
7 if ( p == NULL ) {
printf ( " Out of memory ...\ n " ) ;
9 } else {
printf ( " Memory allocated ...\ n " ) ;
320 Array & Pointer

11 }
/* Out of memory for integer allocation *
13 * while allocating memory space block *
* for 349000000 integers bytes ! */
15 p = malloc ( sizeof ( int ) * 349000000) ;
if ( p == NULL ) {
17 printf ( " Out of memory for integer size ...\ n " ) ;
} else {
19 printf ( " Memory allocated ...\ n " ) ;
}
21 /* Second method of memory allocation . */
if (( p = malloc (100) ) == NULL ) { /* Allocates 100 bytes space . */
23 printf ( " Ooooopps ! Out of memory !\ n " ) ;
exit (1) ;
25 } else {
printf ( " 100 Byte memory allocated ...\ n " ) ;
27 }
/* Free memory */
29 free ( p ) ;
return 0;
31 }
✆✌

Memory allocated ...
Out of memory for integer size ...
100 Byte memory allocated ...
✆✌
The operand of sizeof only has to be parenthesized if it’s a type name, as shown in example
below.

1 float * fp ;
fp = ( float *) malloc ( sizeof ( float ) ) ;
✆✌
If there are the name of a data object instead, then the parentheses can be omitted, but
they rarely are.

int * ip , ar [100];
2 ip = ( int *) malloc ( sizeof ar ) ;
✆✌
In the above example, the array ‘ar’ is an array of 100 integers; after the call to malloc
(assuming that it was successful), ‘ip’ will point to a region of store that can also be treated
as an array of 100 integers. The fundamental unit of storage in C is the character, and
by definition sizeof(char) is equal to 1, so there could allocate space for an array of ten
characters with malloc(10) while to allocate room for an array of ten integers, it have to
use as

malloc ( sizeof ( int [10]) )
✆✌
malloc function should be used cautiously. Loosely use of this function cause memory
leakage. For example,
2.2. POINTER 321


1 void myF () {
int * p =( int *) malloc ( sizeof ( int ) ) ;
3 return ;
}
✆✌
function creates a local pointer with dynamic size of array. But pointer is not freed here.
In this case, the memory contents are not accessible by other pointers with same address.
This is why, memory allocated on heap should always be freed when it is not needed.

void myF () {
2 int * p =( int *) malloc ( sizeof ( int ) ) ;
free ( p ) ;
4 return ;
}
✆✌
If you want to allocate memory and set all memory bits to ‘0s’ then use calloc() function
as given in the following syntax.

1 in * i = ( int *) calloc (5 , sizeof ( int ) ) ;
✆✌
It shall allocate memory space equal to the product of 5 and size of integer, i.e. 20 bytes
and each bit is set to ‘0’. Note that, malloc is much faster than calloc.

Reallocate Memory
realloc() function is used to reallocate the size of the memory block created by the malloc
function previously.

1 realloc ( < ptr > , < new size >)
✆✌
If the new size specify is the same as the old size, realloc changes nothing and return the
same address.

1 # include < stdio .h >
# include < stdlib .h >
3

int main ( int argc , char ** argv ) {


5 int * p = malloc (1024 * sizeof ( int ) ) ;
if ( p == NULL )
7 printf ( " Memory not allocated . " ) ;
int * q = realloc (p , 512 * sizeof ( int ) ) ;
9 if ( q == NULL )
printf ( " Memory not reallocated . " ) ;
11 return 0;
}
✆✌

Memory Management Sometimes, in a string pointer, we erase few memory bytes in a


programming process. These memory bytes remain unused if string array is not refreshed.
For example, we have an array of characters as shown in the following figure.
322 Array & Pointer

1 2 3 4 5 6
ptr G H I J K L

7 8 9 10 11 12
Q R S T U V

13 14 15 16 17 18
[ “ ] ˆ ˙ ‘

The number over the byte are index numbers of the memory byte location. Let the
memory bytes having values Q to V are erased. Now, we rearrange the memory bytes as
shown in the following figure to free some memory space.

1 2 3 4 5 6
ptr G H I J K L

7 8 9 10 11 12
[ “ ] ˆ ˙ ‘

Actually, memory bytes are not shifted leftward, but the contents of the memory
bytes at indices from 13 to 28 are copied into the memory bytes at indices from 7 to 12.
Rearranging of the memory space is good where contents are linear, i.e. contents are not
structured. For example, it is good in case of string, but it is hard to manipulate the
matrix of 6 × 3 order if few memory bytes are erased.

2.2.8 Pointer Arithmetic


In normal mathematics numbers are used for addition, subtraction, division and multipli-
cation etc. A pointer to an integer has different behavior to the integer. This is why, in
pointer arithmetic, we have to arrange or conform the pointers so that they can behave in
properly. A pointer-to-variable always points to the address where value of the variable
is stored. This is why direct arithmetic of the pointers is of the arithmetic of the address
rather than the values stored at the addresses.

# include < stdio .h >
2

int main ( void ) {


4 int a [4] = {50 , 99 , 3490 , 0};
int * p ;
6 p = a;
while (* p > 0) {
8 printf ( " % i \ n " , * p ) ;
/* Go to next integer in memory */
2.2. POINTER 323

10 p ++;
}
12 return 0;
}
✆✌

: - > 50
: - > 99
: - > 3490
✆✌
Another example, using pointer for addition of numbers in an array.

1 # include < stdio .h >

3 int sum_ptr ( char * s ) {


/* Array is passed to function as pointer . *
5 * sum is variable that store result . */
int sum = 0;
7 /* Until the array not become empty . */
while (* s != ’ \0 ’) {
9 /* Get the pointer value and add it to sum . */
sum += * s ;
11 /* Jump to the next pointer position . */
s ++;
13 }
/* Return the answer as sum . */
15 return sum ;
}
17

int main ( int argc , char ** argv ) {


19

/* Array s containing integers . */


21 char s [ ] = {20 , 15 , 50 , 42};
/* Print the answer . */
23 printf ( " Sum : % d \ n " , sum_ptr ( s ) ) ;

25 return 0;
}
✆✌

Sum : 127
✆✌
A pointer based integer array is shown in the following example.

1 # include < stdio .h >
# include < stdlib .h >
3

int main () {
5 int * i ; /* one row multiple columns , 1 Xn array */
int j = 0;
7 i = ( int *) malloc (5 * sizeof ( int ) ) ;
while ( j < 5) {
324 Array & Pointer

9 i [ j ] = j ; /* Assign values to i */
j ++;
11 }
j = 0;
13 while ( j < 5) {
printf ( " % d " , * i ) ;
15 i ++;
j ++;
17 }
return 0;
19 }
✆✌

0 1 2 3 4
✆✌
Pointers follow increment or decrements operations. For example, if pointer ‘i’ represents
to first element of the array (either integer or character type arrays) then ‘i++’ (or ‘i+1’)
represents to the next element of the array. See following figure:

bytes x x x x y y y y z z z z n n n n

i+1

bytes x x x x y y y y z z z z n n n n

i+2

bytes x x x x y y y y z z z z n n n n

Computer Character Codes


In English language, there are 26 alphabets, ten numerals, other punctuation marks
and special characters. These alpha-numeric characters are put in sequence to form
meaning full words. Computer is an electronic device which operates on alternate
current or direct current. There are only two wave forms of alternate current. First is
positive wave form and second is negative wave form. Thus, there is sequences of these
two waveforms when we operate a computer.
2.2. POINTER 325
y

1
1 1 1 1
bits
0 0 0 0
−1

Conventionally, positive waveform is taken as ‘1’ and negative waveform or no


waveform is taken as ‘0’. If computer operates in direct current then there is no negative
wave form to represent ‘0’ bit. In this condition, bit ‘0’ means no current. These
two symbols are binary digits and called as bits. To identify alpha-numeric symbols,
computer uses sequences of these binary digits to form a unique code for each character
or symbol. These unique codes are known as character codes of the computer. Computer
uses eight binary digits for recognition of each character. There are 256 different types
of characters that can be recognized by computer. These 256 characters are assigned
unique decimal character codes ranging from ‘0’ to ‘256’. For example character ‘a’
has character code ‘97’, ‘A’ has character code ‘65’ etc. All the sequential alphabets
and numerals have sequential character codes. For example, upper case alphabets have
character codes ranging from 65 to 90 and lower case alphabets have character codes
ranging from 97 to 122.

Code Symbol Binary


0 00000000
5 00000101
9 00001001
46 . 00101110
47 / 00101111
48 0 00110000
49 1 00110001
50 2 00110010
56 8 00111000
57 9 00111001
65 A 01000001
90 Z 01011010
97 a 01100001
122 z 01111010

Character codes are not same to the user defined binary numbers. This is why,
character code ‘9’ does not represent to numeric decimal ‘9’. Computer accepts ‘9’ as
number digit 9 and computer recognizes it by its equivalent binary sequence 00111001,
i.e. character code 57 rather than binary sequence 00001001. The signal waveform of
326 Array & Pointer

binary 00111001 is given below:


y

0 0 1 1 1 0 0 1
bits

Decimal digit 9

2.2.9 Pointer Address


Pointers are used to point the memory address where data is stored. Four memory bytes
are required for a pointer variable to store the address that it is pointing. During the
declaration of a pointer, data type preceded to it tells the nature of data stored at the
address which is being pointed by it. For example, in the pointer variable declaration

1 string * ptr = new string [8];
✆✌
data type ‘string’ tells that the pointer ‘ptr’ points to memory address 0×00 where a string
of one byte long character is stored. Whenever we will perform pointer’s increment or
decrement operation, like ‘ptr++’ pointer’s pointing address will increase by the size of
character, i.e. one byte. Here, ‘ptr++’ will point to the memory address 0×01 as shown
in the following figure.
*ptr *(ptr++)

d e f g h i j k Bytes
0×00 0×01 0×02 0×03 0×04 0×05 0×06 0×07

ptr ptr++

Again ‘*ptr’ dereference to the character ‘d’ which is stored at the memory ad-
dress pointed by the pointer ‘ptr’. To get the next character ‘e’, dereference is done
as ‘*(ptr++)’. Similarly, if pointer is integer type as declared below:

1 int * ptr = new int [10];
✆✌
The size of the pointer variable is always equal to the address bus size. In 32 bit micro-
processor system, it is 4 bytes long. Now, if pointer ‘prt’ points to the memory address
0×00 then ‘ptr++’ points to the memory address 0×04 as shown in the figure given below:
2.2. POINTER 327

*ptr *(ptr++)

xxxx xxxx xxxx xxxx yyyy yyyy yyyy yyyy Bytes


0×00 0×01 0×02 0×03 0×04 0×05 0×06 0×07

ptr ptr++

Again ‘*ptr’ dereference to the integer value stored at the memory address pointed by
the pointer ‘ptr’. To get the next integer value, de-reference is done as ‘*(ptr++)’.

1 # include < stdio .h >
# define SIZE 4
3

int main ( void ) {


5 short idx ;
double d [ SIZE ];
7 double * ptd ; // data type at pointed address is
// 8 bytes long
9 ptd = d ; // assign address of array to pointer
printf ( " %18 s \ n " , " double " ) ;
11 for ( idx = 0; idx < SIZE ; idx ++)
printf ( " pt + % d : %10 p \ n " ,
13 idx , ptd + idx ) ;
return 0;
15 }
✆✌

double
pt + 0: 0 x 22 cd 30 //
pt + 1: 0 x 22 cd 38 //38 is more than 8 from 30
pt + 2: 0 x 22 cd 40 //40 is more than 16 from 30
pt + 3: 0 x 22 cd 48 //48 is more than 24 from 30
✆✌
The value assigned to a pointer is the address of the object to which it points. The
address of a large object, such as type double variable, typically is the address of the first
byte of the object. Applying the ‘*’ operator to a pointer yields the value stored in the
pointed-to object. Adding ‘1’ to the pointer increases its value by the size, in bytes, of
the pointed-to type. There is close connection between arrays and pointers. They mean
that a pointer can be used to identify an individual element of an array and to obtain its
value. In arrays and pointers

1 arr [ n ] == *( arr + n ) /* same value */
arr +2 == & arr [2] /* same address */
✆✌

# include < stdio .h >
2 # define MONTHS 12

4 int main ( void ) {


int days [ MONTHS ] = {31 , 28 , 31 , 30 , 31 , 30 , \
328 Array & Pointer

6 31 , 31 , 30 , 31 , 30 , 31};
int ind ;
8 for ( ind = 0; ind < MONTHS ; ind ++)
printf ( " Month %2 d has % d days .\ n " , ind + 1 ,
10 *( days + ind ) ) ; // same as days [ ind ]
return 0;
12 }
✆✌

Month 1 has 31 days .
Month 2 has 28 days .
Month 3 has 31 days .
Month 4 has 30 days .
Month 5 has 31 days .
Month 6 has 30 days .
Month 7 has 31 days .
Month 8 has 31 days .
Month 9 has 30 days .
Month 10 has 31 days .
Month 11 has 30 days .
Month 12 has 31 days .
✆✌
Above program can be written as shown below:

# include < stdio .h >
2 # define MONTHS 12

4 int main ( void ) {


int days [ MONTHS ] = {31 , 28 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 ,
31};
6 int ind ;
for ( ind = 0; ind < MONTHS ; ind ++)
8 printf ( " Month %2 d has % d days .\ n " , ind + 1 ,
days [ ind ]) ; // same as *( days + ind )
10 return 0;
}
✆✌

Month 1 has 31 days .
Month 2 has 28 days .
Month 3 has 31 days .
Month 4 has 30 days .
Month 5 has 31 days .
Month 6 has 30 days .
Month 7 has 31 days .
Month 8 has 31 days .
Month 9 has 30 days .
Month 10 has 31 days .
Month 11 has 30 days .
Month 12 has 31 days .
✆✌
2.2. POINTER 329

Here, days is the address of the first element of the array, ‘days + ind’ is the address of
element days[ind] and *(days + ind) is the value of that element, just as days[ind] is.
The loop references each element of the array, in turn, and prints the contents of what it
finds. Another example is

# include < stdio .h >
2

int main () {
4 int * ptr ;
int arrVal [7] = {44 , 55 , 66 , 77};
6 ptr = & arrVal ;
int i ;
8 for ( i = 0; i <= 4; i ++) {
printf ( " arrVal [% d ]: value is % d and address is % p \ n " , i ,
*( ptr + i ) , ( ptr + i ) ) ;
10 }
return 0;
12 }
✆✌

arrVal [0]: value is 44 and address is 0 xbf 85 ad 84
arrVal [1]: value is 55 and address is 0 xbf 85 ad 88
arrVal [2]: value is 66 and address is 0 xbf 85 ad 8 c
arrVal [3]: value is 77 and address is 0 xbf 85 ad 90
✆✌
In C, when an integer is pointed as pointer-to-address-of-integer by a character pointer
variable, then the character variable can addressed to each byte of the integer. An integer
variable is a 4 bytes long. If the address of this integer variable is pointed by character
pointer, i.e. which is one byte long then it can points to each of the byte of the integer
variable. Assume an integer variable is ‘a’. This integer variable is 4 bytes long. The
allocated memory for this integer variable shall be looked like

B[2] B[3] B[4] B[5] B[6] B[7] B[8] B[9] B[10] B[11]

xxxx xxxx xxxx xxxx


a

Here, bytes are labeled as B[2] and so on. The address of integer variable ‘a’ is pointed
by a pointer variable, which is char data type, as shown in syntax given below.

int a ;
2 char * x ;
x = ( char *) & a ;
✆✌
Variable ‘x’ can access to each byte of the integer variable ‘a’.

B[2] B[3] B[4] B[5] B[6] B[7] B[8] B[9] B[10] B[11]

xxxx xxxx xxxx xxxx

x
330 Array & Pointer

See the example below:



1 # include < stdio .h >

3 int main () {
int a ; /* Integer variable . */
5 char * x ; /* Character pointer */
x = ( char *) & a ; /* Pointer to the address of integer . */
7 a = 512;
x [0] = 0; /* Change value of first byte of integer */
9 printf ( " % d \ n " , a ) ;
return 0;
11 }
✆✌

512
✆✌
Initially, the value assigned to integer variable is stored in memory as shown in the figure
given below.

x[3] x[2] x[1] x[0]

00000000 00000000 00000001 00000000


x a

When we change the data of byte x[0] the new value of integer variable ‘a’ is 512. The
above example is modified as

1 # include < stdio .h >

3 int main () {
int a ; /* Declare integer variable . */
5 char * x ; /* Presumes that , data at pointed *
* address is characters type . */
7 x = ( char *) & a ; /* Pointer to the address of integer . */
a = 512;
9 x [0] = 1; /* Change value of first byte of integer */
printf ( " % d \ n " , a ) ;
11 return 0;
}
✆✌

513
✆✌
Now, the memory representation is like

x[3] x[2] x[1] x[0]

00000000 00000000 00000001 00000001


x a

It gives the result a = 513.


2.2. POINTER 331

2.2.10 Pointer to Pointer


Expression of N-element array of pointer ‘ptr’ can be converted into a pointer ‘ptr’ and
its value is the address of first element of the array. If “ptr” is “pointer to char”, then an
expression of type “N-element array of pointer to char” will be converted to “pointer to
pointer to char”.

1 # include < stdio .h >
# include < string .h >
3 # include < stdlib .h >

5 /* The function printIt returns as character pointer */


char * printIt ( const char ** strs , size_t size ) {
7

size_t i , len = 0;
9 for ( i = 0; i < size ; i ++)
len += strlen ( strs [ i ]) ;
11 printf ( " Total characters in array are : % d .\ n " , len ) ;
char * s = malloc ( len * sizeof (* s ) ) ;
13 if (! s ) {
perror ( " Can ’t allocate memory !\ n " ) ;
15 exit ( EXIT_FAILURE ) ;
}
17

for ( i = 0; i < size ; i ++) {


19 strcat (s , strs [ i ]) ;
}
21 return s ;
free ( s ) ;
23 }

25 int main ( void ) {


const char * test [ ] = { " ABC " , " DEF " , " G " , " H " };
27 /* Character pointer for s */
char * s ;
29 /* Character pointer s is pointed - to *
* character pointer printIt */
31 s = printIt ( test , 4) ;
printf ( " Concated string is : % s \ n " , s ) ;
33 /* Free allocated memory that was *
* allocated by function printIt . */
35 free ( s ) ;
return EXIT_SUCCESS ;
37 }
✆✌

Total characters in array are : 8.
Concated string is : ABCDEFGH
✆✌
Another example of the pointer is given below

# include < stdio .h >
332 Array & Pointer

int main ( void ) {


4 /* Character to pointer . */
char ch = ’A ’;
6 char * chptr = & ch ;
/* Integer to pointer . */
8 int i = 20;
int * intptr = & i ;
10 /* Float to pointer . */
float f = 1.20000;
12 float * fptr = & f ;
/* String to pointer . */
14 char * ptr = " It is string . " ;
/* Print all . */
16 printf ( " [% c ] , [% d ] " , * chptr , * intptr ) ;
printf ( " [% f ] , [% c ] " , * fptr , * ptr ) ;
18 printf ( " [% s ]\ n " , ptr ) ;
return 0;
20 }
✆✌

[ A ] , [20] , [1.200000] , [ I ] , [ It is string .]
✆✌
The following is an example for pointer to an array of integer.

1 # include < stdio .h >

3 int main () {
/* Pointer to array having only 5 integer *
5 * elements . Size of integer is four bytes . */
int (* ptr ) [5];
7 /* Array of 5 integers , each integer is 4 bytes long . *
* Elements should equal to the size of pointer to array . */
9 int arr [5] = {1 , 2 , 3 , 4 , 5};
int i ;
11 /* Take the contents of what *
* the array pointer points at */
13 ptr = & arr ;
/* Prints the contents . */
15 for ( i = 0; i < 5; i ++) {
printf ( " value : % d \ n " , (* ptr ) [ i ]) ;
17 }
}
✆✌

value : 1
value : 2
value : 3
value : 4
value : 5
✆✌
2.2. POINTER 333

In above example, if number of elements in pointer to array (ptr) are not equal to the
number of elements in the array (arr) then relation

1 ptr =& arr
✆✌
will give the warning “assignment of incompatible type”. Following is another example
in which pointer to an array of character points to the array of integers. And values are
printed in output at fourth byte position.

1 # include < stdio .h >

3 int main () {
/* Pointer to array of 5 characters . *
5 * Size of each character is one byte . */
char (* ptr ) [5];
7 /* Array of 5 integers , each integer is 4 bytes long . */
int arr [5] = {1 , 2 , 3 , 4 , 5};
9 int i ;
/* Take the contents of what the arr pointer *
11 * points at by the ptr . Here character type *
* pointer points to integer array . Pointer *
13 * ptr is itself one byte long but points to *
*4 byte long integer . So , value shall be *
15 * printed after each four bytes position */
ptr = & arr ;
17 /* Prints the contents . */
for ( i = 0; i <5; i ++) {
19 printf ( " value : % d \ n " , (* ptr ) [ i ]) ;
}
21 }
✆✌

value : 1
value : 0
value : 0
value : 0
value : 2
✆✌
In following example, pointer of array points to the array of characters.

1 # include < stdio .h >

3 int main () {
/* Pointer to array of 5 characters . *
5 * Size of each character is one byte . */
char (* ptr ) [5];
7 /* Array of 5 characters . Each character size is one byte . */
char arr [5] = { ’1 ’ , ’2 ’ , ’3 ’ , ’4 ’ , ’5 ’ };
9 int i ;
/* Take the contents of what the arr *
11 * pointer points at by the ptr . */
ptr = & arr ;
334 Array & Pointer

13 /* Prints the contents . */


for ( i = 0; i < 5; i ++) {
15 printf ( " value : % c \ n " , (* ptr ) [ i ]) ;
}
17 }
✆✌

value : 1
value : 2
value : 3
value : 4
value : 5
✆✌
In the following example, a function prototype

1 char * str_func ( char * str )
✆✌
is declared, which returns a pointer to an character string.

1 # include < stdlib .h >

3 char * str_func ( char * str ) {


/* Flush the pointer value to NULL . */
5 char * s = NULL ;
/* Pass the pointer of str to s *
7 * from the location of str +0. */
s = str ;
9 return s ;
}
11

main ( int argc , char * argvc [ ]) {


13 /* sample string . */
char s [100] = " The Sarnath . " ;
15 char * st ;
/* Pass pointer of char string returned *
17 * by the function str_func ( s ) to st . */
st = str_func ( s ) ;
19 /* Print the result */
printf ( " % s \ n " , st ) ;
21 return 0;
}
✆✌

The Sarnath .
✆✌
Above example is similar to the example given below.

1 # include < stdlib .h >
# define STRLEN 1024
3

char * str_func ( char * str ) {


5 char * s = NULL ;
2.2. POINTER 335

/* Allocate the required memory space . */


7 s = malloc ( sizeof ( char ) *( STRLEN + 1) ) ;
/* Copy contents of str into memory */
9 memcpy (s , str , STRLEN ) ;
/* Return the pointer of memory location */
11 return s ;
free ( s ) ;
13 }

15 main ( int argc , char * argvc [ ]) {


/* sample string . */
17 char s [ STRLEN ] = " The Sarnath . " ;
char * st ;
19 /* Pass pointer of char string returned *
* by the function str_func ( s ) to st . */
21 st = str_func ( s ) ;
/* Print the result */
23 printf ( " % s \ n " , st ) ;
return 0;
25 }
✆✌

The Sarnath .
✆✌
In the following example, we pass the pointer location of ‘str’ pointer to another pointer
‘s’ after increasing the pointer of ‘str’ by char position (equivalent to 2 bytes) in str func()
body.

1 # include < stdlib .h >

3 char * str_func ( char * str ) {


char * s = NULL ;
5 /* Pass the pointer of str to s *
* from the location of str +2. */
7 s = str + 2;
return s ;
9 }

11 main ( int argc , char * argvc [ ]) {


/* sample string . */
13 char s [100] = " The Sarnath . " ;
char * st ;
15 /* Pass pointer of char string returned *
* by the function str_func ( s ) to st . */
17 st = str_func ( s ) ;
/* Print the result */
19 printf ( " % s \ n " , st ) ;
return 0;
21 }
✆✌

e Sarnath .
✆✌
336 Array & Pointer

Again modified form of above example.



1 # include < stdlib .h >

3 char * str_func ( char * str ) {


char * s = NULL ;
5 while (* str != ’ \0 ’ ) {
if (! s && * str == ’ ’) {
7 /* Pass the pointer of str to s *
* from the location of str +1 *
9 * where str has ’ ’ character . */
s = str +1;
11 }
str ++;
13 }
return s ;
15 }

17 main ( int argc , char * argvc [ ]) {


/* sample string . */
19 char s [100] = " The Sarnath . " ;
char * st ;
21 /* Pass pointer of char string returned *
* by the function str_func ( s ) to st . */
23 st = str_func ( s ) ;
/* Print the result */
25 printf ( " % s \ n " , st ) ;
return 0;
27 }
✆✌

Sarnath .
✆✌
Parentheses are used to define the priority of the pointer. See two declarations

1 char * fp () /* Type 1 */
char (* fp ) () /* Type 2 */
✆✌
In first type declaration, ‘fp’ is a function that returns a pointer to char. In second type
declaration the parentheses around ‘*fp’ have the highest priority, so ‘fp’ is a pointer to
a function returning char, i.e. it holds the address of function object which returns char
data type. A pointer of pointer example is given below.

# include < stdio .h >
2 int main () {
int var ; /* Variable var . */
4 int * ptr ; /* Pointer ptr . */
int ** pptr ; /* Pointer of the pointer , pptr . */
6 var = 1234;
/* Take the address of var */
8 ptr = & var ;
/* Take the address of ptr */
2.2. POINTER 337

10 pptr = & ptr ;


/* Read the value using pptr */
12 printf ( " Value of var = % d \ n " , var ) ;
printf ( " Value at * ptr = % d \ n " , * ptr ) ;
14 printf ( " Value at ** pptr = % d \ n " , ** pptr ) ;
return 0;
16 }
✆✌

Value of var = 1234
Value at * ptr = 1234
Value at ** pptr = 1234
✆✌
The memory bytes used by the variables declared in above examples are shown in the
following figure.
var
0×20 0×21 0×22 0×23 0×24 0×25

00000000 00000000 00000100 11010010


var=1234
*ptr
0×40 0×41 0×42 0×43 0×44 0×45

00000000 00000000 00000000 00100001


ptr=&var = 0×21
**pptr
0×60 0×61 0×62 0×63 0×64 0×65

00000000 00000000 00000000 010000001


pptr=&ptr=0×41

Example of pointer to pointer of an array is given below.



1 # include < stdio .h >

3 int main () {
char * ptr = " Arun " ; /* Pointer ptr . */
5 char ** pptr ;
pptr = & ptr ;
7 while (*(* pptr ) != ’ \0 ’) {
printf ( " Value = % c \ n " , *(* pptr ) ) ;
9 (* pptr ) ++;
}
11 return 0;
}
✆✌

Value = A
Value = r
Value = u
Value = n
✆✌
338 Array & Pointer

A r u n
0×51 0×52 0×53 0×54 0×55 0×56 0×57 0×58 0×59

ptr pptr
0×53 0×81

0×81 0×82 0×83 0×84 0×91 0×92 0×93 0×94

From the above example code, the code line



char * ptr = " Arun " ; /* Pointer ptr . */
✆✌
tells that, in memory, string “Arun ” is stored. The memory location at which first
character ‘A’ is stored is assigned to the pointer variable ‘ptr’. Thus ‘ptr’ points to
that memory cell which stores address of ‘A’. From the figure, its value is 0×53. Note
that asterisk used during variable declaration, it makes that variable a pointer. Once
the variable is declared as pointer and if asterisk is prefixed to it, it returns the value
stored at address contains by pointer’s memory cell. After pointer’s declaration, they are
identified by their names without using asterisk prefixed.

1 char ** pptr ;
pptr = & ptr ;
✆✌
These lines tell that second pointer variable ‘pptr’ is declared and address of ‘ptr’ pointer
variable is assigned to it. Thus the memory cell of pointer variable ‘pptr’ holds value 0×81
(let). The memory address of pointer variable ‘pptr’ itself is 0×91.

printf ( " Value = % c \ n " , *(* pptr ) ) ;
✆✌
In above code line ‘*(*pptr))’ has special meaning. Parenthesis are used to define priority.
First we dereference to pointer variable ‘pptr’ as ‘*pptr’. It returns the value stored at
address pointed by pointer variable ‘pptr’. From above figure, the address pointed by
‘pptr’ is 0×81. So, the value at memory address 0×81 is value 0×53. Though this
address is pointer itself, hence the value at this memory address is address of another
memory location. When we dereference this address as ‘*(*pptr)’ (say double dereference
of pointer ‘pptr’) we get the value ‘A’ that is stored at the memory address 0×53. The
code line

1 (* pptr ) ++;
✆✌
adds one in the dereference value of ‘pptr’, actually it is value stored at the memory
address 0×81. This value is address of other location, hence when (*pptr) in incremented
by one, it increases the value 0×53 by one and it becomes 0×54 that is address of string
character ‘r’. Using while loop, we retrieve all the string characters one by one.

1 # include < stdio .h >

3 int main () {
2.2. POINTER 339

int num = 48;


5 int * ptr ;
int ** pptr ;
7 int *** ppptr ;
// *** ppptr = ** pptr = * ptr = num ; //
9 ptr = & num ;
pptr = & ptr ;
11 ppptr = & pptr ;
int i = 1;
13 while ( i < 5) {
printf ( " Value = % d \ n " , *** ppptr + i ) ;
15 i ++;
}
17 return 0;
}
✆✌

Value = 49
Value = 50
Value = 51
Value = 52
✆✌

# include < stdio .h >
2

int main () {
4 int num = 48;
int * ptr ;
6 int ** pptr ;
int *** ppptr ;
8 int **** pppptr ;
ptr = & num ;
10 pptr = & ptr ;
ppptr = & pptr ;
12 pppptr = & ppptr ;
int i = 1;
14 while ( i < 5) {
printf ( " Value = % d \ n " , **** pppptr + i ) ;
16 i ++;
}
18 return 0;
}
✆✌

Value = 49
Value = 50
Value = 51
Value = 52
✆✌

# include < stdio .h >
2

int * sum ( int a , int b ) {


340 Array & Pointer

4 static int k [1];


k [0] = a + b ;
6 return k ;
}
8

int main ( void ) {


10 int * s ;
s = sum (1 , 2) ;
12 printf ( " Sum is : % d \ n " , * s ) ;
return 0;
14 }
✆✌

Sum is : 3
✆✌
The example for the array of pointers to an integer is given below:

1 # include < stdio .h >

3 int main ( void ) {


int i ;
5 int Arr1 [ ] = {1 , 2};
int Arr2 [ ] = {10 , 20};
7 int * ptr [2];

9 ptr [0] = & Arr1 [0];


ptr [1] = & Arr2 [0];
11

for ( i = 0; i < 2; i ++) {


13 printf ( " % d \ t % d \ n " , *( ptr [0] + i ) , *( ptr [1] + i ) ) ;
}
15 return 0;
}
✆✌

1 10
2 20
✆✌
The memory arrangement figure of this example is given below. Integer data type stores
values in group of four bytes. In each group of four bytes, the decimal values of ‘Arr1’
and ‘Arr2’ are shown in the following figure.

Arr1 1 2
0×51 0×52 0×53 0×54 0×55 0×56 0×57 0×58

Arr2 10 20
0×81 0×82 0×83 0×84 0×85 0×86 0×87 0×88

ptr 0×51 0×81

0×91 0×92 0×93 0×94 0×95 0×96 0×97 0×98


2.2. POINTER 341

The stored integer values are small, hence only one byte of group of four bytes has
values and rest has zeros. From the above example code, the code line

int Arr1 [ ] = {1 , 2};
2 int Arr2 [ ] = {10 , 20};
✆✌
declares two arrays, each has two elements. The code line

int * ptr [2];
2

ptr [0] = & Arr1 [0];


4 ptr [1] = & Arr2 [0];
✆✌
declare an array pointer ‘ptr’ of pointer to integers. The array size of the pointer variable
is two. Its first element stored is address of first element of the array ‘Arr1’ and second
element stored is address of first element of the array ‘Arr2’. The code line

printf ( " % d \ t % d \ n " , *( ptr [0] + i ) , *( ptr [1] + i ) ) ;
✆✌
returns the elements of by incrementing pointers for ith array indices. Be cautious about
the addition of one with value of normal variable and value of pointer variable. For
example, if an integer type variable ‘a’ assigned a value 10 and it is added by one as ‘i+1’
then its result will be 11. This is addition of the two integers. But if there is pointer
variable, say ‘*a’ pointing to address of integers, the datasize of pointer variable is always
four bytes, i.e. size of addresses is always four bytes. Let this pointer variable points to
address 0×10. Then addition of one as ‘a+1’ will be equal to the sum of address and size
of address. In this case result be 0×14. Remember that datasize of pointers is four bytes.
The data type precedented to a pointer variable tells about the type of data stored at
the address pointed by it and how the data is read during dereferencing of the pointer.
In the below example, two different pointers has same datasize.

1 # include < stdio .h >

3 int main ( void ) {


char * c ;
5 int * i ;
printf ( " % d \ t % d \ n " , sizeof ( c ) , sizeof ( i ) ) ;
7 return 0;
}
✆✌

4 4
✆✌

int *p[ ];
This declaration is array ‘p’ of pointers to an integer. It means, there are multiple arrays
which stores integer type values. The address of first byte of these arrays are stored at
another places in array form which are pointed by ‘p’.
342 Array & Pointer

Arr1 1 2
0×51 0×52 0×53 0×54 0×55 0×56 0×57 0×58

Arr2 10 20
0×81 0×82 0×83 0×84 0×85 0×86 0×87 0×88

int *p[ ]; 0×51 0×81

0×91 0×92 0×93 0×94 0×95 0×96 0×97 0×98


p

In the above figure, there are two arrays, ‘Arr1’ and ‘Arr2’. The addresses of first
bytes of these two arrays are 0×51 and 0×81 respectively. These addresses are further
arranged in array form whose first byte address (say 0×91) is pointed by pointer ‘p’. A
pointer is always four bytes long in 32 bit system. So, whatever is the size of address of
first bytes, byte address is stored in four bytes long memory space.

int **p[ ];
This declaration stands for array of pointers ‘p’ that point to pointers to integer values.
Let we have two integer variables ‘i’ and ‘j’. These numbers are arranged in memory as
shown in following figure.

int i; int j;
1 2
0×10 0×11 0×12 0×13 0×14 0×15 0×16 0×17 0×18 0×19

0×10 0×16

0×30 0×31 0×32 0×33 0×34 0×35 0×36 0×37 0×38 0×39

int *A; int *B;

The addresses of the integer variables are pointed by pointers ‘A’ and ‘B’ respectively.
The addresses of these two pointers (not pointee) are arranged as array of another pointer
‘p’ as shown in the following figure.

int **p[ ]; 0×30 0×36

0×70 0×71 0×72 0×73 0×74 0×75 0×76 0×77


p

Now, the pointer ‘p’ can be dereferences using this pointer ‘p’. The equivalent C codes
are given below:

1 # include < stdio .h >
2.2. POINTER 343

3 int main () {
int i =1;
5 int j =2;
int * A =& i ;
7 int * B =& j ;
int ** p [2];
9 p [0]=& A ;
p [1]=& B ;
11 printf ( " % d \ n " ,*(*( p [0]) ) ) ;
printf ( " % d \ n " ,*(*( p [1]) ) ) ;
13 return 0;
}
✆✌

1
2
✆✌

int (*p)[ ];
This is explained as pointer ‘p’ to an array of integers. Parentheses enclosing ‘*p’ has
higher priority, hence pointer definition goes with ‘p’ while array definition (by []) goes
to values stored at pointee address. Let we have an array ‘Arr’.

Arr 12345 12346


0×10 0×11 0×12 0×13 0×14 0×15 0×16 0×17

int (*p)[ ]; 0×10

0×30 0×31 0×32 0×33 0×34 0×35 0×36 0×37


p
The pointer ‘p’ points to the first element of the array ‘Arr’ as shown in above figure.
The C equivalent codes are given below:

# include < stdio .h >
2

int main () {
4 int Arr [2]={12345 ,12346};
int (* p ) [2];
6 p =& Arr ;
printf ( " % d \ n " ,(* p ) [0]) ;
8 printf ( " % d \ n " ,(* p ) [1]) ;
return 0;
10 }
✆✌

12345
12346
✆✌
344 Array & Pointer

int (**p)[ ];
It constructs a pointer ‘p’ which points to the address of another pointer to an array of
integers. The memory arrangement and its relation is shown in the following figure.

Arr1 1 2
0×10 0×11 0×12 0×13 0×14 0×15 0×16 0×17

int (*A)[ ]; 0×10

0×20 0×21 0×22 0×23 0×24 0×25 0×26 0×27

int (**p)[ ]; 0×20

0×30 0×31 0×32 0×33 0×34 0×35 0×36 0×37


p
C codes for above declaration are given below:

# include < stdio .h >
2

int main ( void ) {


4 int Arr [2]={1 ,2};
int * A ;
6 A =& Arr [0];
int ** p ;
8 p =& A ;
printf ( " % d \ n " , ** p ) ;
10 return 0;
}
✆✌

1
✆✌

int *(*p)[ ];
It constructs a pointer ‘p’ which points to the array of pointers those are pointing to
integers. The memory arrangement and its relation is shown in the following figure.
2.2. POINTER 345

i 1
0×51 0×52 0×53 0×54 0×55 0×56 0×57 0×58

j 10
0×61 0×62 0×63 0×64 0×65 0×66 0×67 0×68

int *P[ ]; 0×51 0×61

0×71 0×72 0×73 0×74 0×75 0×76 0×77 0×78

int *(*p)[ ]; 0×71

0×81 0×82 0×83 0×84 0×85 0×86 0×87 0×88


p
The C example is

1 # include < stdio .h >

3 int main ( void ) {


int i = 105 , j = 201;
5 int * A [2] = {& i , & j };
int *(* p ) [];
7 p =& A ;
printf ( " % d \ t % d \ n " , *(* p ) [0] , *(* p ) [1]) ;
9 return 0;
}
✆✌

105 201
✆✌

int (*p[ ])[ ];


It constructs array of pointer ‘p’ which points to the array of integers. The memory
arrangement and its relation is shown in the following figure.

Arr1 1 2
0×51 0×52 0×53 0×54 0×55 0×56 0×57 0×58

Arr2 10 20
0×81 0×82 0×83 0×84 0×85 0×86 0×87 0×88

int (*p[ ])[ ]; 0×51 0×81

0×91 0×92 0×93 0×94 0×95 0×96 0×97 0×98


p
The C example is given below:
346 Array & Pointer


1 # include < stdio .h >

3 int main ( void ) {


int Arr1 [2] = {1 , 2};
5 int Arr2 [2] = {4 , 5};
int (* p [2]) [2];
7 p [0] = & Arr1 ;
p [1] = & Arr2 ;
9 printf ( " % d \ t % d \ n " , (* p [0]) [1] , (* p [1]) [0]) ;
return 0;
11 }
✆✌

2 4
✆✌

int *p();
It constructs a function which returns a pointer pointing to an integer value. The memory
arrangement of this declaration is shown below:

int v;
0x14AEFC
0×30 0×31 0×32 0×33 0×34 0×35 0×36 0×37

int *p(); 0×32

0×91 0×92 0×93 0×94 0×95 0×96 0×97 0×98


p

C code for above declaration are given below. In this example, the returned pointer
pointed to an integer value.

1 # include < stdio .h >

3 int * p ( int * j ) {
* j = 10 * (* j ) ;
5 return j ;
}
7

int main ( void ) {


9 int v = 10;
printf ( " % d \ n " , * p (& v ) ) ;
11 return 0;
}
✆✌

100
✆✌
We can also return a pointer which points to a real value, like double or float type values.
See the example given below:
2.2. POINTER 347


1 # include < stdio .h >

3 double * p ( double * j ) {
* j = 10 * (* j ) ;
5 return j ;
}
7

int main ( void ) {


9 double v = 10;
printf ( " % lf \ n " , * p (& v ) ) ;
11 return 0;
}
✆✌

100.000000
✆✌

int (*p)();
It constructs a pointer ‘p’ which points to a function which returns an integer value. The
C codes are

1 int myf ( int r ) {
return 2* r ;
3 }
(* p ) () =& myf ;
✆✌
The memory arrangement and its relation is shown in the following figure.

myf 3.14
0×30 0×31 0×32 0×33 0×34 0×35 0×36 0×37

int (*p)(); 0×32

0×91 0×92 0×93 0×94 0×95 0×96 0×97 0×98


p

int (**p)();
It constructs a pointer ‘p’ which points to another pointer to a function. The function
being pointed here returns an integer value.
348 Array & Pointer

myf 100
0×30 0×31 0×32 0×33 0×34 0×35 0×36 0×37

int (*f)(); 0×32

0×81 0×82 0×83 0×84 0×85 0×86 0×87 0×88


f

int (**p)(); 0×81

0×91 0×92 0×93 0×94 0×95 0×96 0×97 0×98


p

In the above figure, the function ‘myf’ returns the pointer address of computed value
‘100’ via a pointer variable ‘j’. Pointer variable ‘j’ points to the address of 0×22 (for
example). The C equivalent codes are given below:

# include < stdio .h >
2

int myf ( int j ) {


4 j = 10 * j ;
return j ;
6 }

8 int main ( void ) {


int v = 10;
10 int (* f ) () ;
int (** p ) () ;
12 f = & myf ;
p = &f;
14 printf ( " % d \ n " , (** p ) ( v ) ) ;
return 0;
16 }
✆✌

100
✆✌

int *(*p)();
It constructs a pointer ‘p’ which points to a function. The function being pointed here
returns pointer to an integer value.
2.2. POINTER 349
j=0×22
100
0×20 0×21 0×22 0×23 0×24 0×25 0×26 0×27

myf 0×22
0×30 0×31 0×32 0×33 0×34 0×35 0×36 0×37

int *(*p)(); 0×32

0×91 0×92 0×93 0×94 0×95 0×96 0×97 0×98


p

The C equivalent codes are given below:



1 # include < stdio .h >

3 int * myf ( int * j ) {


* j = 10 * (* j ) ;
5 return j ;
}
7

int main ( void ) {


9 int v = 10;
int *(* p ) () ;
11 p =& myf ;
printf ( " % d \ n " , *(* p ) (& v ) ) ;
13 return 0;
}
✆✌

100
✆✌

int (*p())();
It constructs a function ‘p’, which returns value of a pointer to function (say ‘myf’), where
function ‘myf’ returns an integer value.

myf 100
0×30 0×31 0×32 0×33 0×34 0×35 0×36 0×37

p 0×32
0×40 0×41 0×42 0×43 0×44 0×45 0×46 0×47

The equivalent C codes are given below:


350 Array & Pointer


1 # include < stdio .h >

3 int myf ( int j ) {


j = 10 * j ;
5 return j ;
}
7

int * p ( int * j ) {
9 j = myf (* j ) ;
return j ;
11 }

13 int main ( void ) {


int v = 11;
15 int *(* p () ) () ;
printf ( " % d \ n " , * p (& v ) ) ;
17 return 0;
}
✆✌

110
✆✌

int (*p[ ])();


It constructs an array of pointers ‘p’ which points to the address of functions. Functions
returns integer type value.

myf1 12
0×30 0×31 0×32 0×33 0×34 0×35 0×36 0×37

myf2 13
0×40 0×41 0×42 0×43 0×44 0×45 0×46 0×47

int (*p[])(); 0×32 0×42

0×91 0×92 0×93 0×94 0×95 0×96 0×97 0×98


p

The C codes are



1 # include < stdio .h >

3 int myf1 ( int j ) {


return 10 * j ;
5 }

7 int myf2 ( int j ) {


return 5 * j ;
2.2. POINTER 351

9 }

11 int main ( void ) {


int v = 11;
13 int (* p [2]) () ;
p [0]=& myf1 ;
15 p [1]=& myf2 ;
printf ( " % d \ t % d \ n " , (* p [0]) ( v ) ,(* p [1]) ( v ) ) ;
17 return 0;
}
✆✌

110 55
✆✌

int (*p())[ ];
It constructs a function ‘p’ which returns a pointer value. The return pointer points to
an array of integers.

j[] 100 200


0×20 0×21 0×22 0×23 0×24 0×25 0×26 0×27

myf 0×20
0×30 0×31 0×32 0×33 0×34 0×35 0×36 0×37

The C codes are



1 # include < stdio .h >
int j [2]={100 ,200};
3

int * myf () {
5 return j ;
}
7

int main ( void ) {


9 int (* myf () ) [];
printf ( " % d \ t % d \ n " , (* myf () ) [0] , (* myf () ) [1]) ;
11 return 0;
}
✆✌

100 200
✆✌
352 Array & Pointer

2.2.11 Pointer Casting


Suppose a pointer is declared as

1 int * i ;
✆✌
It declares a variable that points to the address of other variable. This declaration also
tells about the data type of pointed address. In above declaration, the address, which
‘i’ will point, shall be integer type. In other words, the data started from the pointed
address shall be grouped in four successive bytes. See the code snippets

1 unsigned int i =1818004170;
int * j =& i ; // let address of i is 0 x21
3 printf ( " % d " ,* j ) ; // call value started at address 0 x21
✆✌

0×20 0×21 0×22 0×23 0×24 0×25


00110110 00101110 10001010 11001010
i = 1818004170

Data type int for the pointer ‘j’ tells us that when we retrieve data from the address of
‘i’, data must be read from four successive memory bytes started at the address of
‘i’ and onward. If address data type is different from the data type of the pointer itself,
then pointers are typecast suitably to tell the compiler about the number of bytes being
read or write at once started from the address. Normally, in pointer casting, data size of
the pointer and address pointed by the pointer are made equal. See the following code
snippets.

1 # include < stdio .h >

3 int main () {
/* A double floating type value . */
5 double d =1000000.22 25 5;
/* A pointer of long int type . */
7 long int * iptr ;
/* Cast address of the double floating *
9 * type number into the long int type . */
iptr =( long int *) & d ;
11 /* Retrieve value from the address pointed *
* by iptr and convert it into double type . */
13 printf ( " % lf " , *( double *) iptr ) ;
return 0;
15 }
✆✌

1000000.2225 50
✆✌
2.2. POINTER 353

2.2.12 Pointer as Structure


A structure object can be assigned to a pointer to object by assigning it the address of
the structure object.

1 # include < stdio .h >

3 struct Struc {
int i ;
5 char ch ;
};
7

int main ( void ) {


9 /* Structure object obj */
struct Struc obj ;
11 /* Pointer structure object strucObj *
* assigned the address of obj */
13 struct Struc * strucObj = & obj ;

15 /* Assign values to elements of structure */


strucObj - > i = 5;
17 strucObj - > ch = ’A ’;

19 /* Access value of elements of structure */


printf ( " [% d ] [% c ]\ n " , strucObj - > i , strucObj - > ch ) ;
21 return 0;
}
✆✌

[5] [ A ]
✆✌
In the above example, code line

1 struct Struc obj ;
✆✌
creastes a structure object ‘obj’. The code line

1 struct Struc * strucObj = & obj ;
✆✌
creates pointer struct object ‘strucObj’ and the address of ‘obj’ is assigned to it. Now
the structure elements can be accessed by using pointer object and using operator ‘−>’
as shown in above example.
354 File & Data Structure
3.1. INPUT OUTPUT 355

3 File & Data Structure

Standard Input-Output and access of files is a main part of computer programming.


In this chapter we shall discuss the importance and methodology of accessing system and
user define files.

3.1 Input Output


A C program under execution opens automatically three standard streams named stdin,
stdout, and stderr. These are attached to every C program. The first standard stream
is used for input buffering and the other two are used for outputs. These streams are
sequences of bytes.

1 int main () {
int var ;
3 /* Use stdin for scanning an *
* integer from keyboard . */
5 scanf ( " % d " , & var ) ;
/* Use stdout for printing a character . */
7 printf ( " % d " , var ) ;
return 0;
9 }
✆✌
By default stdin points to the keyboard and stdout and stderr point to the screen. It is
possible under Unix and may be possible under other operating systems to redirect input
from or output to a file or both.

3.1.1 Handling File Directory


Sometimes user needs to read, create, delete or change a directory. Directories are sep-
arated by symbol ‘/’. To represent current working directory or parent directory of the
current working directory, dots are used as ‘./’ and ‘../’ respectively. ‘/..’ has same
meaning as ‘/’.

3.1.2 Change Directory


Current working directory of a program is the location where all the temporary or per-
manent files are stored and retrieved by default. Location of current working directory of
a program may be changed to other directory by using chdir () function. Syntax of this
function is

1 chdir ( < directory path >)
✆✌
On successful change of location of old working directory to new location of working
directory, it returns ‘0’ otherwise ‘-1’. An example of the function is given below.
356 File & Data Structure


1 # include < stdio .h >
# include < string .h >
3 # include < stdlib .h >

5 int main ( void ) {


char dr [10];
7 int ret ;
printf ( " Enter the directory name : " ) ;
9 scanf ( " % s " , & dr ) ;
ret = chdir ( dr ) ;
11 printf ( " % d \ n " , ret ) ;
return EXIT_SUCCESS ;
13 }
✆✌

3.1.3 FILE pointers


The <stdio.h>header contains a definition for a type FILE (usually via a data type)
which is capable of processing all the information needed to exercise control over a stream,
including its file position indicator, a pointer to the associated buffer (if any), an error
indicator that records whether a read/write error has occurred and an end-of-file indicator
that records whether the end of the file has been reached. There may be multiple FILE
descriptors for a single file.

1 # include < stdio .h >

3 int main ( void ) {


FILE * f1 , * f2 ;
5 /* First discriptor for file a . txt */
f1 = fopen ( " a . txt " , " r " ) ;
7 if (! f1 ) {
printf ( " Unable to open file a . txt \ n " ) ;
9 return 1;
}
11 /* Second discriptor for file a . txt */
f2 = fopen ( " a . txt " , " r " ) ;
13 if (! f2 ) {
printf ( " Unable to open file a . txt \ n " ) ;
15 return 1;
}
17

/* Change f1 location */
19 fseek ( f1 , 7 , SEEK_SET ) ;

21 /* Change f2 location */
fseek ( f2 , 14 , SEEK_SET ) ;
23 /* Print results */
printf ( " Position of f1 is % d \ n " , ftell ( f1 ) ) ;
25 printf ( " Position of f2 is % d \ n " , ftell ( f2 ) ) ;
/* close streams */
3.1. INPUT OUTPUT 357

27 fclose ( f1 ) ;
fclose ( f2 ) ;
29 return 0;
}
✆✌

Position of f 1 is 7
Position of f 2 is 14
✆✌
But this way of accessing file is not safe as both file descriptors access file simultaneously.
To avoid any problems arise due to mixing of streams and descriptors, a file locking facility
should be used to avoid simultaneous access.

Locking & Unlocking a File


The flockfile() function acquires the internal locking to the file stream. It ensures that no
other stream may access the file while the file is locked and accessed by current stream. If
there is no further required to access the file, then file is unlocked by funlockfile() function.
funlockfile() function is called if locking function is able to lock the file.

# include < stdio .h >
2 # include < stdlib .h >

4 int main ( void ) {


FILE * f1 , * f2 ;
6 /* first discriptor for file a . txt */
f1 = fopen ( " a . txt " , " r " ) ;
8 /* lock the file */
flockfile ( f1 ) ;
10 if (! f1 ) {
printf ( " Unable to open file a . txt \ n " ) ;
12 return 1;
}
14 /* change f1 location */
fseek ( f1 , 7 , SEEK_SET ) ;
16 printf ( " Position of f1 is % d \ n " , ftell ( f1 ) ) ;
/* unlock the file */
18 funlockfile ( f1 ) ;
/* close streams */
20 fclose ( f1 ) ;

22 return 0;
}
✆✌

Position of f 1 is 7
✆✌
But direct locking of the file by flockfile() function may return error if the file is already
locked. So, it is safe to use ftrylockfile() function to avoid multiple locking of the same
file simultaneously.
358 File & Data Structure


1 # include < stdio .h >
# include < stdlib .h >
3

int main ( void ) {


5 FILE * f1 , * f2 ;
/* first discriptor for file a . txt */
7 f1 = fopen ( " a . txt " , " r " ) ;
/* lock the file */
9 ftrylockfile ( f1 ) ;
if (! f1 ) {
11 printf ( " Unable to open file a . txt \ n " ) ;
return 1;
13 }
/* change f1 location */
15 fseek ( f1 , 7 , SEEK_SET ) ;
printf ( " Position of f1 is % d \ n " , ftell ( f1 ) ) ;
17 /* unlock the file */
funlockfile ( f1 ) ;
19 /* close streams */
fclose ( f1 ) ;
21

return 0;
23 }
✆✌

Position of f 1 is 7
✆✌
In the above example, we are trying to lock a file by using function ftrylockfile() and
seeking file stream location in the file. If the file is already locked by other program,
then ftrylockfile() function will fail to lock the file and stream will try to access the file
without locking it (simultaneous access). This is why, before accessing to the file, its
locking status must be checked.

1 # include < stdio .h >
# include < stdlib .h >
3

int main ( void ) {


5 FILE * f1 , * f2 ;
/* first discriptor for file a . txt */
7 f1 = fopen ( " a . txt " , " r " ) ;
/* try to lock the file and check lock status */
9 if ( ftrylockfile ( f1 ) == 0) {
if (! f1 ) {
11 printf ( " Unable to open file a . txt \ n " ) ;
return 1;
13 }
/* change f1 location */
15 fseek ( f1 , 7 , SEEK_SET ) ;
printf ( " Position of f1 is % d \ n " , ftell ( f1 ) ) ;
17 }
/* unlock the file */
3.1. INPUT OUTPUT 359

19 funlockfile ( f1 ) ;
/* close streams */
21 fclose ( f1 ) ;
return 0;
23 }
✆✌

Position of f 1 is 7
✆✌

Reading/Scanning Directory
In C, there is no dedicated function to read or scan a directory but using readdir or
scandir function, a directory can be read or scanned respectively.

1 # include < stdio .h >
# include < dirent .h >
3

int main () {
5 DIR * dir ;
struct dirent * dp ;
7 char * file_name ;
dir = opendir ( " . " ) ;
9 while (( dp = readdir ( dir ) ) != NULL ) {
printf ( " debug : % s \ n " , dp - > d_name ) ;
11 if (! strcmp ( dp - > d_name , " . " ) || ! strcmp ( dp - > d_name , " .. " ) ) {
/* your code here . */
13 } else {
file_name = dp - > d_name ; // use it
15 printf ( " file_name : \"% s \"\ n " , file_name ) ;
}
17 }
closedir ( dir ) ;
19 return 0;
}
✆✌

debug : .
debug : ..
debug : nbproject
file _ name : " nbproject "
debug : main . c
file _ name : " main . c "
✆✌
Similarly

# include < dirent .h >
2

int main ( void ) {


4 struct dirent ** namelist ;
int n ;
6
360 File & Data Structure

n = scandir ( " . " , & namelist , NULL , alphasort ) ;


8 if ( n < 0)
perror ( " scandir " ) ;
10 else {
while (n - -) {
12 printf ( " % s \ n " , namelist [ n ] - > d_name ) ;
free ( namelist [ n ]) ;
14 }
free ( namelist ) ;
16 }
}
✆✌

nbproject
main . c
image . bmp
dist
..
.
✆✌

Open a File
To open or close a file, the <stdio.h>library has three functions: fopen, freopen, and
fclose. We can open a file to read or write as

# include < stdio .h >
2 FILE * fopen ( const char * filename , const char * mode ) ;
FILE * freopen ( const char * filename , const char * mode , FILE * stream ) ;
✆✌
fopen and freopen opens the file whose name is in the string pointed-by a file name and
associates a stream with it. Both return a pointer to the object controlling the stream.
If the open operation fails, a null pointer is returned and error is set. On successfully
opening of a file, the error and end-of-file indicators are cleared. freopen differs from
fopen by a bit and the file pointed-by ‘stream’ is firstly closed if it already open and
errors related to close operation are ignored. File operation mode for both file opening
functions points-to a string consisting of one of the following sequences:
3.1. INPUT OUTPUT 361

Mode Explanation
r Open a text file for reading
w Truncate to zero length or create a text file for writing
a Append or open or create text file for writing at end-of-file
rb Open binary file for reading
wb Truncate to zero length or create a binary file for writing
ab Append or open or create binary file for writing at end-of-file
r+ Open text file for update (reading and writing)
w+ Truncate to zero length or create a text file for update
a+ Append or open or create text file for update
r+b or rb+ Open binary file for update (reading and writing)
w+b or wb+ Truncate to zero length or create a binary file for update
a+b or ab+ Append or open or create binary file for update

Table 3.1: File read and write mode.

Opening a file with read mode (‘r’ as the first character in the mode argument) fails
if the file does not exist or can not be read. Opening a file with append mode (‘a’ as
the first character in the mode argument) causes all subsequent writes to the file to be
forced to the then-current end-of-file. Opening a binary file with append mode (‘b’ as
the second or third character in the above list of mode arguments) may initially position
the file position indicator for the stream beyond the last data written, because of null
character padding. When a file is opened with update mode (‘+’), both input and output
may be performed on the associated stream.

1 # include < stdio .h >
# include < stdlib .h >
3

int main ( void ) {


5 /* File pointer that is defined in stdlib . h header *
* file and used for file handling by data type FILE */
7 FILE * fo ;
char f_name [10]= " fname . txt " ;
9 /* Open file fname . txt in write mode */
fo = fopen ( f_name , " w " ) ;
11 /* Show warning if file can not be open . */
if ( fo == NULL ) {
13 printf ( " Could not open fname file .\ n " ) ;
exit (0) ;
15 } else {
printf ( " % s file is created .\ n " , f_name ) ;
17 }
int i = 0 , n ;
362 File & Data Structure

19 /* Get the rows up to which data *


* is to be write in the file */
21 printf ( " Enter the data rows No . : " ) ;
scanf ( " % d " , & n ) ;
23 /* Do what you want . */
while ( i < n ) {
25 fprintf ( fo , " % d % d % d \ n " , i , i *i , i * i * i ) ;
i ++;
27 }
printf ( " Details are written in file % s .\ n " , f_name ) ;
29 /* Close the open file . */
fclose ( fo ) ;
31 /* If every thing gone ok , return success . */
return 0;
33 }
✆✌

fname . txt file is opened .
Enter the data rows No . : 10
Details are written in file fname . txt
✆✌

Close a File
We can close a file pointer by using close function as shown in the following syntax.

1 # include < stdio .h >
int fclose ( FILE * stream ) ;
✆✌
The fclose() function causes the stream pointed-by ‘stream’ to be flushed and the as-
sociated file is closed. Any unwritten buffered data for the stream are delivered to the
host environment to be written to the file. Any unread buffered data are discarded. The
function returns zero if the stream was successfully closed or stream is encounters with
EOF.

# include < stdio .h >
2 # include < stdlib .h >

4 int main ( void ) {


/* File pointer that is defined in stdlib . h header *
6 * file and used for file handling by data type FILE */
FILE * fo ;
8 char f_name [10]= " fname . txt " ;
/* Open file fname . txt in write mode */
10 fo = fopen ( f_name , " w " ) ;
/* Show warning if file can not be open . */
12 if ( fo == NULL ) {
printf ( " Could not open fname file .\ n " ) ;
14 exit (0) ;
} else {
16 printf ( " % s file is created .\ n " , f_name ) ;
3.1. INPUT OUTPUT 363

}
18 int i = 0 , n ;
/* Get the rows up to which data *
20 * is to be write in the file */
printf ( " Enter the data rows No . : " ) ;
22 scanf ( " % d " , & n ) ;
/* Do what you want . */
24 while ( i < n ) {
fprintf ( fo , " % d % d % d \ n " , i , i *i , i * i * i ) ;
26 i ++;
}
28 printf ( " Details are written in file % s .\ n " , f_name ) ;
/* Close the open file . */
30 fclose ( fo ) ;
printf ( " % s file is closed .\ n " , f_name ) ;
32 /* If every thing gone ok , return success . */
return 0;
34 }
✆✌

fname . txt file is opened .
Enter the data rows No . : 10
Details are written in file fname . txt
fname . txt file is closed .
✆✌

fflush function The synopsis of this function is



# include < stdio .h >
2 int fflush ( FILE * stream ) ;
✆✌
If stream points to output or update stream in which the most recent operation was not
input, the fflush function causes any unwritten data for that stream to be deferred to the
host environment to be written to the file. A simple example is

# include < stdio .h >
2 /* For prototype for sleep () */
# include < unistd .h >
4

int main ( void ) {


6 int count ;
for ( count = 10; count >= 0; count - -) {
8 /* Lead with a CR */
printf ( " \ rSeconds until launch : " ) ;
10 if ( count > 0)
printf ( " %2 d " , count ) ;
12 else
printf ( " blastoff !\ n " ) ;
14 /* Force output now !! */
fflush ( stdout ) ;
16 /* The sleep () delayed system by number of seconds : */
sleep (1) ;
364 File & Data Structure

18 }
return 0;
20 }
✆✌

Seconds until launch : 10
Seconds until launch : blastoff !
✆✌
The effect of using fflush() on an input stream is undefined. Sometime a program needed
huge RAM and disk memory to perform a programming job. In between the process
of job, if there is requirement of log data (say) to be stored in disk (outstream), then
OS waits till termination of the resource consuming program and then it writes log data
into the disk file. If the program abrupptly terminated or terminated with error, whole
unwritten log data is vanished. To overcome this problem, fflush function is used to force
OS to write log data immediated into the disk file. It is good programming habbit that
each time when data file being written by program (like using function fprintf etc), it
should be followed by fflush function.
setbuf function The syntax of this function is

# include < stdio .h >
2 void setbuf ( FILE * stream , char * buf ) ;
✆✌
It returns no value. The setbuf function is equivalent to the setvbuf function. setvbuf
function uses two more parameters ‘mode’ and ‘size’. A simple example is

# include < stdio .h >
2

int main () {
4 FILE * fp ;
char lineBuf [1024];
6 /* b . txt must be in executable ’s dir */
fp = fopen ( " b . txt " , " rb " ) ;
8 setbuf ( fp , NULL ) ; // set to unbuffered
fclose ( fp ) ;
10 return 0;
}
✆✌

setvbuf function The function syntax is



1 # include < stdio .h >
int setvbuf ( FILE * stream , char * buf , int mode , size_t size ) ;
✆✌
The setvbuf function may be used only after the stream pointed-by ‘stream’ has been
associated with an open file and before any other operation is performed on the stream.
The argument size specifies the ‘size’ of the array. The contents of the array at any time
are indeterminate. The setvbuf function returns zero on success, or nonzero if an invalid
value is given for ‘mode’ or if the request cannot be honored. A simple example is

# include < stdio .h >
3.1. INPUT OUTPUT 365

int main () {
4 FILE * fp ;
char lineBuf [1024];
6 /* b . txt must be in executable ’s dir */
fp = fopen ( " b . txt " , " r " ) ;
8 /* set to line buffering */
setvbuf ( fp , lineBuf , _IOLBF , 1024) ;
10 fclose ( fp ) ;
return 0;
12 }
✆✌
setvbuf is invoked with ‘mode’ has value IOFBF and ‘size’ when ‘buf’ is not a null
pointer. Again, if ‘buf’ is a null pointer then ‘mode’ has value IONBF.
fgetpos & fsetpos functions The function syntax is

# include < stdio .h >
2 int fgetpos ( FILE * stream , fpos_t * pos ) ;
int fsetpos ( FILE * stream , const fpos_t * pos ) ;
✆✌
The fgetpos function stores the current value of the file position indicator for the stream
pointed-by ‘stream’ in the object pointed-by ‘pos’. A simple example is

1 # include < stdio .h >

3 int main () {
FILE * fName ;
5 int c ;
int n ;
7 fpos_t pos ;

9 fName = fopen ( " fname . txt " , " r " ) ;


if ( fName == NULL )
11 perror ( " Can not open a file . " ) ;
else {
13 c = fgetc ( fName ) ;
printf ( " First char is % c \ n " , c ) ;
15 fgetpos ( fName , & pos ) ;
for ( n = 0; n < 3; n ++) {
17 fsetpos ( fName , & pos ) ;
c = fgetc ( fName ) ;
19 printf ( " Char in position % d is % c \ n " , n , c ) ;
}
21 fclose ( fName ) ;
}
23 return 0;
}
✆✌

First char is 0
Char in position 0 is
366 File & Data Structure

Char in position 1 is
Char in position 2 is
✆✌

fseek & ftell functions The function syntax is



# include < stdio .h >
2 int fseek ( FILE * stream , long int offset , int whence ) ;
long ftell ( FILE * stream ) ;
✆✌
The fseek function sets the file position indicator for the stream pointed-to the ‘stream’.
For a binary stream, the new position, measured in characters from the beginning of the
file, is obtained by adding ‘offset’ to the position specified by ‘whence’. Three macros
in stdio.h called SEEK SET, SEEK CUR, and SEEK END expand to unique values. If
the position specified by ‘whence’ is SEEK SET, the specified position is the beginning
of the file; if ‘whence’ is SEEK END, the specified position is the end of the file; and
if ‘whence’ is SEEK CUR, the specified position is the current file position. A binary
stream need not meaningfully support fseek calls with a ‘whence’ value of SEEK END.
In case of SEEK END, ‘offset’ may be a negative count (i.e. within the current extent of
file) or may be a positive count (i.e. position past the current end of file). In the later
case file is extended up to that position and filled with zeros.

0 1 2 3 4 5 6 7 8 9
(1)

10 11 12 13 14 15 16 17 18 19

20 21 22 23 24 25 26 27 28 29
(2)

(4)
fp
fseek(fp, 10, SEEK CUR)
fp
(3)

Figure 3.1: Change in location of file pointer from current file pointer location.
3.1. INPUT OUTPUT 367

0 1 2 3 4 5 6 7 8 9
(1)

10 11 12 13 14 15 16 17 18 19

20 21 22 23 24 25 26 27 28 29
(2)

fp
(4)
fseek(fp, -8, SEEK END)
fp
(3)

Figure 3.2: Change in location of file pointer from the end of file location.

0 1 2 3 4 5 6 7 8 9
(1)

10 11 12 13 14 15 16 17 18 19
(4)

20 21 22 23 24 25 26 27 28 29
(2)

fp
fseek(fp, 10, SEEK SET)
fp
(3)

Figure 3.3: Change in location of file pointer from the beginning of file location.

A simple example is

1 # include < stdio .h >

3 int main () {
FILE * fp ;
5

fp = fopen ( " file . txt " , " w + " ) ;


7 fputs ( " This is my file name . " , fp ) ;

9 fseek ( fp , 7 , SEEK_SET ) ;
fputs ( " C Programming Langauge " , fp ) ;
11 fclose ( fp ) ;

13 return (0) ;
}
✆✌
368 File & Data Structure

For output see the file “file.txt”. ftell returns the current position of file pointer from the
start of the file. Its largest return value is signed long type value. When ftell is used for
obtaining of size of huge files, it fails due to its return size, therefore be cautious when
using for this purpose. Example for ftell is given below:

# include < stdio .h >
2

int main () {
4 FILE * fp ;
int len ;
6

fp = fopen ( " file . txt " , " r " ) ;


8 if ( fp == NULL ) {
perror ( " Error opening file " ) ;
10 return ( -1) ;
}
12 fseek ( fp , 0 , SEEK_END ) ;

14 len = ftell ( fp ) ;
fclose ( fp ) ;
16

printf ( " Total size of file . txt = % d bytes \ n " , len ) ;


18

return (0) ;
20 }
✆✌

Total size of file . txt = 32 bytes
✆✌
Using the pointer in a function, we can also get the file size as shown in the example given
below.

1 # include < stdlib .h >
# include < stdio .h >
3

long getFileSize ( const char * filename ) {


5 long result ;
FILE * fh = fopen ( filename , " rb " ) ;
7 fseek ( fh , 0 , SEEK_END ) ;
result = ftell ( fh ) ;
9 fclose ( fh ) ;
return result ;
11 }

13 int main ( void ) {


printf ( " % ld \ n " , getFileSize ( " file . txt " ) ) ;
15 return 0;
}
✆✌

Total size of file . txt = 32 bytes
✆✌
3.1. INPUT OUTPUT 369

fseek and fputc can be used to write a file of specific size. See the example given below.

1 # include < stdio .h >

3 int main () {
FILE * fp = fopen ( " myfile . txt " , " w " ) ;
5 fseek ( fp , 1024 * 1024 , SEEK_SET ) ;
fputc ( ’\ n ’ , fp ) ;
7 fclose ( fp ) ;
return 0;
9 }
✆✌

rewind function The synopsis of the function is



1 # include < stdio .h >
void rewind ( FILE * stream ) ;
✆✌
The rewind function sets the file position indicator for the stream pointed-by ‘stream’ to
the beginning of the file. It is equivalent to

( void ) fseek ( stream , 0L , SEEK_SET )
✆✌
except that the error indicator for the stream is also cleared. A simple example is

1 # include < stdio .h >

3 int main () {
FILE * fp ;
5 int ch ;

7 fp = fopen ( " file . txt " , " r " ) ;

9 if ( fp != NULL ) {
while (! feof ( fp ) ) {
11 ch = fgetc ( fp ) ;
printf ( " % c " , ch ) ;
13 }
rewind ( fp ) ;
15

while (! feof ( fp ) ) {
17 ch = fgetc ( fp ) ;
printf ( " % c " , ch ) ;
19 }
fclose ( fp ) ;
21 }

23 return (0) ;
}
✆✌
The output from the file “file.txt” is
370 File & Data Structure


This is C Programming Langauge
This is C Programming Langauge
✆✌

feof function The synopsis of the function is



# include < stdio .h >
2 int feof ( FILE * stream ) ;
✆✌
The feof function tests the end-of-file indicator for the stream pointed-by ‘stream’ and
returns nonzero if and only if the end-of-file indicator is set for stream, otherwise it returns
zero. A simple example is

# include < stdio .h >
2

int main ( void ) {


4 int a ;
FILE * fp ;
6 fp = fopen ( " file . txt " , " rb " ) ;
/* Read single ints at a time , stopping on EOF or error : */
8 while ( fread (& a , sizeof ( int ) , 1 , fp ) , ! feof ( fp ) &&
! ferror ( fp ) ) {
printf ( " I read % d \ n " , a ) ;
10 }
if ( feof ( fp ) )
12 printf ( " End of file was reached .\ n " ) ;
if ( ferror ( fp ) )
14 printf ( " An error occurred .\ n " ) ;
fclose ( fp ) ;
16 return 0;
}
✆✌

I read 543649385
I read 1735287116
I read 1701279073
End of file was reached .
✆✌

Reading File
There are two ways to read the stuff in C. In first method data is accepted from terminal.
In second method data is read from a file. Following functions are used in reading data
from a file.
fgetc function The syntax of the function is

# include < stdio .h >
2 int fgetc ( FILE * stream ) ;
✆✌
3.1. INPUT OUTPUT 371

The fgetc function obtains the next character (if present) as an unsigned1 char converted
into its equivalent character code, from the input stream pointed-by ‘stream’. fgetc mod-
ified to the file pointer after reading each character. If the stream is at end-of-file, the
end-of-file indicator for the stream is set and fgetc returns EOF. If a read error occurs,
the error indicator for the stream is set and fgetc returns EOF.

fgetc(fp)

fp→ A B C D E F G H

fgetc(fp)

fp→ A B C D E F G H


# include < stdio .h >
2 # include < stdlib .h >

4 int main ( void ) {


/* File pointer */
6 FILE * fr ;
/* Open file fread . txt in read mode */
8 fr = fopen ( " fname . txt " , " r " ) ;
/* If file is not opened , show warning *
10 * and exit without doing nothing . */
if ( fr == NULL ) {
12 printf ( " Couldn ’ t open fname . txt file for reading .\ n " ) ;
}
14 /* Read whole data of file by using fgetc */
int c ;
16 while (( c = fgetc ( fr ) ) != EOF ) {
putchar ( c ) ;
18 }
/* Close the file */
20 fclose ( fr ) ;
/* If every thing is ok return successfully */
22 return 0;
}
✆✌

1
Position of char is determined by integer number started from zero to continue...
372 File & Data Structure


This is C Programming Langauge
✆✌
fgetc() is more faster than the fread () function. fread () takes 0.1143 seconds to read
1.8MB MP3 file while fgetc takes 0.000142 seconds to read the same file.

1 # include < stdio .h >
# include < time .h >
3

int main () {
5 clock_t startTime = clock () ;
FILE * fp ;
7 fp = fopen ( " a . mp3 " , " r " ) ;
int s ;
9 s = fgetc ( fp ) ;
while ( s > 0) {
11 s = fgetc ( fp ) ;
}
13 fclose ( fp ) ;
clock_t endTime = clock () ;
15 double td = ( endTime - startTime ) / ( double ) CLOCKS_PER_ SE C ;
printf ( " Program has run for %5.8 f seconds \ n " , td ) ;
17 return 0;
}
✆✌

fgets function The synopsis of the function is



char * fgets ( char *s , int n , FILE * stream ) ;
✆✌
The fgets function reads at most one less than the number of characters specified by
‘n’ from the stream pointed-by ‘stream’ into the array pointed-by ‘s’. No additional
characters are read after a new-line character (which is retained) or after end-of-file. A
null character is written immediately after the last character read into the array. The
fgets function returns ‘s’ if successful. If end-of-file is encountered and no characters have
been read into the array, the contents of the array remain unchanged and a null pointer is
returned. If a read error occurs during the operation, the array contents are indeterminate
and a null pointer is returned.

s=ABCDE

fgets(s,5,fp)

fp→ A B C D E F G H

In following example, fgets() function reads specific number of bytes from a file via
file pointer and prints it in output console.

1 # include < stdio .h >
3.1. INPUT OUTPUT 373

# define BUFFER_SIZE 100


3

int main ( void ) {


5 /* A read buffer */
char buffer [ BUFFER_SIZE ];
7 while ( fgets ( buffer , BUFFER_SIZE , stdin ) != NULL ) {
printf ( " % s " , buffer ) ;
9 }
return 0;
11 }
✆✌

This is
This is
my Car
my Car
✆✌
Note that each line ends with end of line marker, i.e. ‘\r\n’, therefore, fgets always returns
a string of size two bytes even if a blank line is read from flat text file.

# include < stdio .h >
2 # include < string .h >

4 int main () {
FILE * f ;
6 int i = 0;
char * line = malloc (1024) ;
8 f = fopen ( " txt . txt " , " r " ) ;
if ( f ) {
10 while ( fgets ( line , 1024 , f ) != NULL ) {
i = 0;
12 while ( line [ i ] != ’ \0 ’) {
printf ( " % d % d % d \ t " , line [ i ] , ’\ r ’ , ’\ n ’) ;
14 i ++;
}
16 printf ( " \ n " ) ;
}
18 free ( line ) ;
}
20 fclose ( f ) ;
return 0;
22 }
✆✌

13 13 10 10 13 10
97 13 10 98 13 10 99 13 10
13 13 10 10 13 10
✆✌
Another example, with additional functionality is given below. The texts from ‘fname.txt’
file are read and prints it in output console.

1 # include < stdio .h >
374 File & Data Structure

# include < stdlib .h >


3 # define BUFFER_SIZE 1000

5 int main ( void ) {


/* File pointer */
7 FILE * fr ;
/* A read buffer */
9 char buffer [1000];
/* Open file fname . txt in read mode */
11 fr = fopen ( " fname . txt " , " r " ) ;
/* If file is not opened , show warning *
13 * and exit without doing nothing . */
if ( fr == NULL ) {
15 printf ( " Couldn ’ t open fname . txt file for reading .\ n " ) ;
return 0;
17 }
/* Read whole data of file by using fgets */
19 while ( fgets ( buffer , BUFFER_SIZE , fr ) != NULL ) {
printf ( " % s " , buffer ) ;
21 }
/* Close the file . */
23 fclose ( fr ) ;
/* If every thing is ok return successfully */
25 return 0;
}
✆✌

This is C Programming Langauge
✆✌
fgets can also used in place of scanf for receiving string from standard input.

1 # include < stdio .h >
# define STRSIZE 100
3

int main () {
5 int res ;
char * str1 , * str2 ;
7

str1 = malloc ( sizeof ( char ) * STRSIZE + 1) ;


9 printf ( " First string : " ) ;
fgets ( str1 , STRSIZE , stdin ) ;
11 printf ( " You entered : % s " , str1 ) ;

13 str2 = malloc ( sizeof ( char ) * STRSIZE + 1) ;


printf ( " Second string : " ) ;
15 fgets ( str2 , STRSIZE , stdin ) ;
printf ( " You entered : % s " , str2 ) ;
17

free ( str1 ) ;
19 free ( str2 ) ;

21 return 0;
3.1. INPUT OUTPUT 375

}
✆✌

First string : aryb
You entered : aryb
Second string : rakv
You entered : rakv
✆✌

getc function This function reads data from input stream character by character,
unlike to gets which reads string at once. Though this function has time consuming
process, yet it is helpful in bytewise operations. This function reads data from file and
updates its address by one. This function stops reading data when it encounters EOF
symbol or any process error. The synopsis of the function getc is

# include < stdio .h >
2 int getc ( FILE * stream ) ;
✆✌
The getc function is equivalent to fgetc, except that it may be implemented as a macro.

# include < stdio .h >
2 # include < stdlib .h >
# define BUFFER_SIZE 1000
4

int main ( void ) {


6 /* File pointer */
FILE * fr ;
8 /* A read buffer */
char buffer [1000];
10 /* Open file fname . txt in read mode */
fr = fopen ( " fname . txt " , " r " ) ;
12 /* If file is not opened , show warning *
* and exit without doing nothing . */
14 if ( fr == NULL ) {
printf ( " Couldn ’ t open fname . txt file for reading .\ n " ) ;
16 return 0;
}
18 /* Read whole data of file by using getc */
int c ;
20 while (( c = getc ( fr ) ) != EOF ) {
putchar ( c ) ;
22 }
/* Close the file . */
24 fclose ( fr ) ;
/* If every thing is ok return successfully */
26 return 0;
}
✆✌

getchar function The syntax of this function is



1 /* Header file for getchar () . */
376 File & Data Structure

# include < stdio .h >


3 int getchar ( void ) ;
✆✌
The getchar function is equivalent to getc with the argument stdin. The getchar function
returns the next character from the input stream pointed-by stdin. The return value is
character code (integer) of the character. For example it returns ‘97’ for character ‘a’,
‘98’ for character ‘b’ and so on. It is similar to the following statement.

1 scanf ( " % c " , & ch ) ;
✆✌
Example of this function is given below.

1 # include < stdio .h >
/* Copy input to output */
3

void main ( void ) {


5 int c ;
/* Get the position of first character *
7 * of stuff supplied to console window . */
c = getchar () ;
9 /* Recurse while loop until the character *
* representing end of file is not encountered */
11 while ( c != EOF ) {
/* Put the first character and reach to next *
13 * character if next character is no EOF */
putchar ( c ) ;
15 /* After putting previous character *
* read the position of next character */
17 c = getchar () ;
}
19 }
✆✌
We can also count the lines by using getchar function

1 # include < stdio .h >

3 /* Count lines in input */


main ( void ) {
5 /* Define required variables . */
int c , nl ;
7 /* Initiate start of line number */
nl = 0;
9 /* Until end of file is not *
* encountered recurse while loop . */
11 while (( c = getchar () ) != EOF )
/* If new line parameter \ n is encountered increase *
13 * the line counter and print the line number . */
if ( c == ’\ n ’)
15 ++ nl ;
printf ( " % d \ n " , nl ) ;
17 }
✆✌
3.1. INPUT OUTPUT 377

The third one is



1 # include < stdio .h >
/* As the word is count , enter into the *
3 * word to count characters in a word */
# define INSIDEWORD 1
5 /* If all characters are counted *
* exit and start word count mode . */
7 # define OUTWORD 0

9 main ( void ) {
/* Define parameters */
11 int c , Noline , Noword , Nocharacter , state ;
/* Initial state is in word mode */
13 state = OUTWORD ;
/* Initiate counters as zero */
15 Noline = Noword = Nocharacter = 0;
/* Until not encountered end of file do *
17 * recursion for while loop for each character . */
while (( c = getchar () ) != EOF ) {
19 /* Count the character until \ n or *
* ’ ’ or \ t is not encountered */
21 ++ Nocharacter ;
/* If encountered end of line \ n */
23 if ( c == ’\ n ’)
/* Count the line */
25 ++ Noline ;
/* If encountered to space or end of line or *
27 * tab , enter into word mode to count the words . */
if ( c == ’ ’ || c == ’\ n ’ || c == ’\ t ’)
29 /* Change the state to word mode when *
* encountered with ’ ’ or \ n or \ t controls . */
31 state = OUTWORD ;
/* If word mode count the words */
33 else if ( state == OUTWORD ) {
/* Toggle the state to character mode until *
35 * encountered with ’ ’ or \ n or \ t controls . */
state = INSIDEWORD ;
37 /* Count the words . */
++ Noword ;
39 }
}
41 printf ( " Number of lines & words are % d & % d .\ n " , Noline ,
Noword ) ;
printf ( " Number of characters are % d \ n " , Nocharacter ) ;
43 }
✆✌
Following is an example of finding longest line.

1 # include < stdio .h >
/* Maximum input line length */
3 # define MAXLINE 1000
378 File & Data Structure

int readline ( char line [ ] , int maxline ) ;


5 void copyoutput ( char to [ ] , char from [ ]) ;

7 main ( void ) {
/* Current line length */
9 int len ;
/* Maximum length seen so far */
11 int max ;
/* Current input line */
13 char line [ MAXLINE ];
/* Longest line saved here */
15 char longest [ MAXLINE ];
max = 0;
17 while (( len = readline ( line , MAXLINE ) ) > 0) {
if ( len > max ) {
19 max = len ;
copyoutput ( longest , line ) ;
21 }
}
23 /* There was a line */
if ( max > 0)
25 printf ( " % s " , longest ) ;
return 0;
27 }

29 /* readline : read a line into s , return length */


int readline ( char s [ ] , int lim ) {
31 int c , i ;
for ( i = 0; i < lim - 1 && \
33 ( c = getchar () ) != EOF && \
c != ’ \ n ’; ++ i )
35 s[i] = c;
if ( c == ’\ n ’) {
37 s[i] = c;
++ i ;
39 }
s [ i ] = ’ \0 ’;
41 return i ;
}
43

/* copyoutput : copyoutput ’ from ’ into *


45 * ’ to ’; assumed that it is big enough */
void copyoutput ( char to [ ] , char from [ ]) {
47 int i ;
i = 0;
49 while (( to [ i ] = from [ i ]) != ’ \0 ’ )
++ i ;
51 }
✆✌

gets function The syntax of the function is



3.1. INPUT OUTPUT 379

1 # include < stdio .h >


char * gets ( char * s ) ;
✆✌
The gets function reads characters from the input stream pointed-by stdin into the array
pointed-by ‘s’ until an end-of-file is encountered or a new-line character is read. Any
new-line character is discarded, and a null character is written immediately after the last
character read into the array. This function is deprecated as it’s dangerous, it may cause
buffer overflow.

# include < stdio .h >
2 # define STRSIZE 100

4 int main () {
int res ;
6 char * str1 , * str2 ;

8 str1 = malloc ( sizeof ( char ) * STRSIZE + 1) ;


printf ( " First string : " ) ;
10 gets ( str1 ) ;
printf ( " You entered : % s \ n " , str1 ) ;
12

str2 = malloc ( sizeof ( char ) * STRSIZE + 1) ;


14 printf ( " Second string : " ) ;
gets ( str2 ) ;
16 printf ( " You entered : % s \ n " , str2 ) ;

18 free ( str1 ) ;
free ( str2 ) ;
20

return 0;
22 }
✆✌

First string : aryb
You entered : aryb
Second string : rakv
You entered : rakv
✆✌

EOF pitfall EOF is a negative value defined in <stdio.h>, usually -1. The reason
is that, the keyboard input ranges from 0 to 255 in extended character support. So any
other value except than -1 will interpret as a character rather than termination of a file.
A mistake when using fgetc, getc, or getchar is to assign the result to a variable of type
char before comparing it to ‘EOF’. The following code fragments exhibit this mistake,
and next code fragments exhibits the correct approach (using type int)

/* c as character . */
2 char c ;
while (( c = getchar () ) != EOF )
4 putchar ( c ) ;
✆✌
380 File & Data Structure

The mistake in above example is corrected in the following example.



/* c as integer */
2 int c ;
while (( c = getchar () ) != EOF )
4 putchar ( c ) ;
✆✌

scanf function The synopsis of the function is



# include < stdio .h >
2 int fscanf ( FILE * stream , const char * format , variable_nam e ) ;
int scanf ( const char * format , variable_nam e ) ;
4 int sscanf ( const char * src , const char * format , dest ) ;
✆✌
The fscanf function reads input from the stream pointed-by ‘stream’, under control of
the string pointed-by ‘format’ that specifies the admissible sequences and how they are
to be converted for assignment, using subsequent arguments as pointers to the objects to
receive converted input. If there are insufficient arguments for the format, the behavior
is undefined. If the format is exhausted while arguments remain, the excess arguments
are evaluated (as always) but are otherwise ignored. The format shall be a multi-byte
character sequence, beginning and ending in its initial shift state. A simple example is

# include < stdio .h >
2

int main ( int argc , char * argv [ ]) {


4 char key [10];
int Hex , i ;
6 strcpy ( key , " zaz " ) ;
sscanf ( key , " % x " , & Hex ) ;
8 printf ( " The Hex value of ’% s ’ is ’% x ’.\ n " , key , Hex ) ;
return 0;
10 }
✆✌

The Hex value of ’ zaz ’ is ’22 d 000 ’.
✆✌
fscanf example is given as

1 # include < stdio .h >
# include < stdlib .h >
3

int main () {
5 int num ;
FILE * fp ;
7 /* file . txt must be in the executable ’s dir */
fp = fopen ( " file . txt " , " r " ) ;
9 /* Read file in integer form . */
fscanf ( fp , " % d " , & num ) ;
11 printf ( " Integer % d .\ n " , num ) ;
/* Read file in hex form . */
13 fscanf ( fp , " % x " , & num ) ;
3.1. INPUT OUTPUT 381

printf ( " Hex is % x .\ n " , num ) ;


15 /* Read file in string form . */
fscanf ( fp , " % s " , & num ) ;
17 printf ( " String is % c .\ n " , num ) ;
fclose ( fp ) ;
19

return (0) ;
21 }
✆✌
Output from my file “file.txt” is

Integer 0.
Hex is 0.
String is T .
✆✌
Following is a fscanf example.

1 # include < stdio .h >

3 int main ( int argc , char * argv [ ]) {


FILE * fin ; // In file name
5 FILE * fout ; // Out file name
/* Must provide infile name and outfile name from command line */
7 if ( argc < 3) {
printf ( " Use : % s < file in > < file out >\ n " , argv [0]) ;
9 exit (1) ;
}
11 fin = fopen ( argv [1] , " r " ) ; // open infile for read
if ( fin == NULL ) { // if any error
13 fprintf ( stderr , " Can ’t open in file in . list !\ n " ) ;
exit (1) ;
15 }
/* Open outfile for read */
17 fout = fopen ( argv [2] , " w " ) ;
if ( fout == NULL ) { // if any error
19 fprintf ( stderr , " Can ’t open out file in . list !\ n " ) ;
exit (1) ;
21 }
/* Read name array from first column of infile */
23 char Name [9];
/* Read roll no from second column of infile */
25 int RolNo ;
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -**
27 Infile structure is like
Arun 100
29 Raj 200
Ram 300
31 and saved in . txt file
Scan file line by two columns
33 at once until file is not ended .
** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
35 while ( fscanf ( fin , " % s % d " , Name , & RolNo ) != EOF ) {
382 File & Data Structure

/* Write every thing in out file if first column is *


37 * text column and second column is integer column . */
fprintf ( fout , " % s % d \ n " , Name , RolNo ) ;
39 }
/* Close infile and outfile . */
41 fclose ( fin ) ;
fclose ( fout ) ;
43 return 0;
}
✆✌

fread function The syntax of the function is



# include < stdio .h >
2 size_t fread ( void * ptr , size_t size , size_t nmemb , FILE * stream );
✆✌
The fread function reads from the stream pointed-by ‘stream’ and writes data into the
array pointed-by ‘ptr’, up to ‘nmemb’ elements whose size is specified by ‘size’. A simple
example is

# include < stdio .h >
2

int main ( void ) {


4 int i ;
int n [10];
6 FILE * fp ;
fp = fopen ( " a . txt " , " rb " ) ;
8 fread (n , sizeof ( int ) , 10 , fp ) ; // read 10 integers
fclose ( fp ) ;
10 // print them out :
for ( i = 0; i < 10; i ++)
12 printf ( " n [% d ] == % d \ n " , i , n [ i ]) ;
return 0;
14 }
✆✌
Output for my file “a.txt” is

n [0] == 1936287828
n [1] == 544434464
n [2] == 539444064
n [3] == 1735357008
n [4] == 1835884914
✆✌
A second example is

1 # include < stdio .h >
# define bufsize 10
3

int main ( int argc , char * argv [ ]) {


5 int s ;
int HexValue ;
7 char buf [ bufsize ];
3.1. INPUT OUTPUT 383

/* ’f ’ prefixed with ’ read ’ and ’ write ’ functions *


9 * represents to the file to be read and write . */
s = fread ( buf , 1 , bufsize , stdin ) ;
11 while ( s > 0) {
fwrite ( buf , 1 , s , stdout ) ;
13 s = fread ( buf , 1 , bufsize , stdin ) ;
}
15 return 0;
}
✆✌
There are no differences between reading one byte long data from a file by ‘n’ times or
‘n’ bytes long data by one time, using function fread (). In both cases, fread () stores ‘n’
bytes data from file pointer into buffer pointer. Only execution time is affected on the
implementation type of fread (). In following example, a 5.48MB file is read one byte at
once. The execution time is about 1.188 seconds.

# include < stdio .h >
2 # include < time .h >
# define DATA_SIZE 1
4 # define BLOCK_SIZE 1

6 int main () {
clock_t startTime = clock () ;
8 FILE * fp ;
/* bmp . bmp must be in the executable ’s dir */
10 fp = fopen ( " bmp . bmp " , " r " ) ;
char buff [1024];
12 int s ;
s = fread ( buff , DATA_SIZE , BLOCK_SIZE , fp ) ;
14 while ( s > 0) {
s = fread ( buff , DATA_SIZE , BLOCK_SIZE , fp ) ;
16 }
fclose ( fp ) ;
18 clock_t endTime = clock () ;
double td = ( endTime - startTime ) / ( double ) CLOCKS_PER_ SE C ;
20 printf ( " Program has run for %5.8 f seconds \ n " , td ) ;
return 0;
22 }
✆✌
Data size is increased from 1 to 10, the execution time reduced to 0.125 seconds.

# include < stdio .h >
2 # include < time .h >
# define DATA_SIZE 10
4 # define BLOCK_SIZE 1

6 int main () {
clock_t startTime = clock () ;
8 FILE * fp ;
/* bmp . bmp must be in the executable ’s dir */
10 fp = fopen ( " bmp . bmp " , " r " ) ;
384 File & Data Structure

char buff [1024];


12 int s ;
s = fread ( buff , DATA_SIZE , BLOCK_SIZE , fp ) ;
14 while ( s > 0) {
s = fread ( buff , DATA_SIZE , BLOCK_SIZE , fp ) ;
16 }
fclose ( fp ) ;
18 clock_t endTime = clock () ;
double td = ( endTime - startTime ) / ( double ) CLOCKS_PER_ SE C ;
20 printf ( " Program has run for %5.8 f seconds \ n " , td ) ;
return 0;
22 }
✆✌
Again, data size is 1 and block size read by fread () function is increased to 10 from 1.
Again the execution time is 0.125 seconds.

# include < stdio .h >
2 # include < time .h >
# define DATA_SIZE 1
4 # define BLOCK_SIZE 10

6 int main () {
clock_t startTime = clock () ;
8 FILE * fp ;
/* bmp . bmp must be in the executable ’s dir */
10 fp = fopen ( " bmp . bmp " , " r " ) ;
char buff [1024];
12 int s ;
s = fread ( buff , DATA_SIZE , BLOCK_SIZE , fp ) ;
14 while ( s > 0) {
s = fread ( buff , DATA_SIZE , BLOCK_SIZE , fp ) ;
16 }
fclose ( fp ) ;
18 clock_t endTime = clock () ;
double td = ( endTime - startTime ) / ( double ) CLOCKS_PER_ SE C ;
20 printf ( " Program has run for %5.8 f seconds \ n " , td ) ;
return 0;
22 }
✆✌
Hence, it is clear that when block size read by fread () function increases, the corresponding
execution time decreases.

Writing File
We can write a binary or text file by using following methods.
fputc function The synopsis of the function is

# include < stdio .h >
2 int fputc ( int c , FILE * stream ) ;
✆✌
3.1. INPUT OUTPUT 385

The fputc function writes the character specified by ‘c’ (converted to an unsigned char)
to the stream pointed-by ‘stream’ at the position indicated by the associated file position
indicator (if defined), and advances the indicator appropriately. If the file cannot sup-
port positioning requests, or if the stream is opened with append mode, the character
is appended to the output stream. The function returns the character written, unless a
write error occurs, in which case the error indicator for the stream is set and fputc returns
EOF.

# include < stdio .h >
2 # include < stdlib .h >

4 int main ( int argc , char ** argv ) {


int i = 0;
6 FILE * fp ;
fp = fopen ( " a . txt " , " wa " ) ;
8 while ( i < 100) {
fputc (i , fp ) ;
10 i ++;
}
12 close ( fp ) ;
return ( EXIT_SUCCESS ) ;
14 }
✆✌

fputs function The synopsis of the function is



# include < stdio .h >
2 int fputs ( const char *s , FILE * stream ) ;
✆✌
The fputs function writes the string pointed-by ‘s’ to the stream pointed-to ‘stream’. The
terminating null character is not written. The function returns EOF if a write error
occurs, otherwise it returns a non-negative value. A simple example is

# include < stdio .h >
2 # include < stdlib .h >

4 int main ( int argc , char ** argv ) {


char s [10] = " hello " ;
6 FILE * fp ;
fp = fopen ( " a . txt " , " wa " ) ;
8 fputs (s , fp ) ;
close ( fp ) ;
10 return ( EXIT_SUCCESS ) ;
}
✆✌

putc function This function has syntax like



1 # include < stdio .h >
int putc ( int c , FILE * stream ) ;
✆✌
386 File & Data Structure

The putc function is equivalent to fputc, except that if it is implemented as a macro, it


may evaluate stream more than once, so the argument should never be an expression with
side effects. The function returns the character written, unless a write error occurs, in
which case the error indicator for the stream is set and the function returns EOF.

# include < stdio .h >
2 # include < stdlib .h >

4 int main ( int argc , char ** argv ) {


int i = 0;
6 FILE * fp ;
fp = fopen ( " a . txt " , " wa " ) ;
8 while ( i < 100) {
putc (i , fp ) ;
10 i ++;
}
12 close ( fp ) ;
return ( EXIT_SUCCESS ) ;
14 }
✆✌

putchar function The syntax of this function is



/* Header file for putchar () . */
2 # include < stdio .h >
int putchar ( int c ) ;
✆✌
The putchar function is equivalent to putc with the second argument stdout. It returns
the character equivalent to its character code. If a write error occurs, the error indicator
for stdout is set and the function returns EOF. This is similar to the statement

1 printf ( " % c " , ch ) ;
✆✌
A simple example is

1 # include < stdio .h >
# include < stdlib .h >
3

int main ( int argc , char ** argv ) {


5 int i =0;
while (i <100) {
7 putchar ( i ) ;
i ++;
9 }
return ( EXIT_SUCCESS ) ;
11 }
✆✌

puts function The synopsis of the function is



1 # include < stdio .h >
int puts ( const char * s ) ;
✆✌
3.1. INPUT OUTPUT 387

The puts function writes the string pointed-by ‘s’ to the stream pointed-to stdout, and
appends a new-line character to the output. The terminating null character is not written.
The function returns EOF if a write error occurs; otherwise, it returns a non-negative
value.

# include < stdio .h >
2 # include < stdlib .h >

4 int main ( int argc , char ** argv ) {


char s [10] = " hello " ;
6 puts ( s ) ;
return ( EXIT_SUCCESS ) ;
8 }
✆✌
Each puts puts a value at the beginning of new line. See the example as given bellow:

# include < stdio .h >
2 # include < stdlib .h >

4 int main ( int argc , char ** argv ) {


puts ( " This is new line " ) ;
6 puts ( " This is new line " ) ;
puts ( " This is new line " ) ;
8 return ( EXIT_SUCCESS ) ;
}
✆✌

This is new line
This is new line
This is new line
✆✌

fwrite function The synopsis of the function is



1 # include < stdio .h >
size_t fwrite ( const void * ptr , size_t size , size_t nmemb , FILE
* stream ) ;
✆✌
The fwrite function writes, from the array pointed-by ‘ptr’, up to ‘nmemb’ elements whose
size is specified by ‘size’ to the stream pointed-to ‘stream’. The file position indicator for
the stream (if defined) is advanced by the number of characters successfully written. A
simple example is

# include < stdio .h >
2

int main ( void ) {


4 int i ;
int r [10];
6 FILE * fp ;
/* Populate the array with random numbers : */
8 for ( i = 0; i < 10; i ++) {
r [ i ] = rand () ;
388 File & Data Structure

10 }
/* Save the random numbers (10 ints ) to the file */
12 fp = fopen ( " a . txt " , " wb " ) ;

14 /* Write 10 ints */
fwrite (r , sizeof ( int ) , 10 , fp ) ;
16 fclose ( fp ) ;
return 0;
18 }
✆✌
fwrite function writes bytes into the file stream rather than string data. This is why
integer values can not be written into text file by using this function.
fprintf function Integers can be written into a text file by using fprintf function rather
than fwrite function. fprintf, first converts an integer into its equivalent character code
and then puts it into the file stream. An example for the fprintf function is given below:

# include < stdio .h >
2

int main () {
4 FILE * f ;
int i = 0;
6 f = fopen ( " TreeNode . txt " , " w " ) ;
while ( i < 5) {
8 fprintf (f , " % d \ n " , 10 + i ) ;
i ++;
10 }
fclose ( f ) ;
12 return 0;
}
✆✌
In output file, output appears as

10
11
12
13
14
✆✌

Supplying File Names from Command Line There is another way by which file names
can be directly supplied to the program and the files are read and write as stdin and
stdout. For explanation see following example.

1 # include < stdio .h >
# define buf_size 1024
3

int main ( int argc , char * argv [ ]) {


5 char buf [ buf_size ];
int rd ;
7 if ( argc < 2) {
/* In command line a infile name can be assigned by *
3.1. INPUT OUTPUT 389

9 * prefixing ’<’ character and outfile name can be *


* assigned by prefixing ’>’ character before input *
11 * and output file names . If system can able to read *
* the file it shown not error and put all the data *
13 * of infile into outfile . If file does not exist *
* then system return that ’ The system can not find *
15 * the file specified . ’ Other string which is not *
* prefixed by ’<’ or ’>’ is considered as argument . */
17 fprintf ( stderr , " % s key < infile > outfile \ n " , argv [0]) ;
exit (1) ;
19 }
/* Infile is read as ’ stdin ’ */
21 rd = fread ( buf , 1 , buf_size , stdin ) ;
while ( rd > 0) {
23 /* Outfile is open as ’ stdout ’. If *
* outfile is not specified , output *
25 * is printed in the console window . */
fwrite ( buf , 1 , rd , stdout ) ;
27 rd = fread ( buf , 1 , buf_size , stdin ) ;
}
29 /* File open for read and write once would be *
* closed automatically when program is terminated . */
31 }
✆✌

Remove & Rename a File

remove function This function removes the specified file whose name is supplied as
argument from the disk storage. The syntax of this function is

1 # include < stdio .h >
int remove ( const char * filename ) ;
✆✌
It returns zero if file is successfully removed otherwise non zero if removal of file is unsuc-
cessful. The remove function causes the file whose name is the string pointed-by ‘filename’
to be no longer accessible by that name.

# include < stdio .h >
2

int main () {
4 if ( remove ( " fname . txt " ) != 0)
perror ( " Error deleting file " ) ;
6 else
puts ( " File successfully deleted " ) ;
8 return 0;
}
✆✌

File successfully deleted
✆✌
390 File & Data Structure

unlink function It deletes a file identify by file name. If file name is supplied to
the function file itself is also deleted. Actually, if any process has the file open when
this happens, deletion is postponed until all processes have closed the file. The function
unlink () is declared in the header file ‘unistd.h’. It returns 0 on successful completion,
and -1 on error.

1 # include < stdio .h >
# include < unistd .h >
3

int main ( void ) {


5 unlink ( " a . txt " ) ;
return 0;
7 }
✆✌

rmdir function It deletes a directory identify by directory name. It is similar to


unlink () except that the error handling is improved in rmdir () function. It returns 0 on
successful completion, and -1 on error.

1 # include < stdio .h >
# include < unistd .h >
3

int main ( void ) {


5 rmdir ( " ../ " ) ;
return 0;
7 }
✆✌

rename function The synopsis of the function is



1 # include < stdio .h >
int rename ( const char * old_name , const char * new_name ) ;
✆✌
The rename function causes the file whose name is the string pointed-by ‘old name’ to
be henceforth known by new name, pointed-by ‘new name’. A simple example is

# include < stdio .h >
2

int main () {
4 if ( rename ( " a . txt " , " b . txt " ) != 0)
perror ( " Error renaming file " ) ;
6 else
puts ( " File successfully renamed . " ) ;
8 return 0;
}
✆✌

Error renaming file : No such file or directory
✆✌

tmpfile function The synopsis of the function is


3.1. INPUT OUTPUT 391


1 # include < stdio .h >
FILE * tmpfile ( void ) ;
✆✌
The tmpfile function creates a temporary binary file. This file is automatically removed
when either it is closed or the program, which created it, is terminated. A simple example
is

# include < stdio .h >
2 FILE * fp ;

4 int main () {
/* Initiate a temporary file . */
6 fp = tmpfile () ;
if (! fp ) {
8 printf ( " Couldn ’ t initiate temp file ...\ n " ) ;
exit (0) ;
10 } else {
printf ( " temp file is initiated ... " ) ;
12 }
return 0;
14 }
✆✌

temp file is initiated ...
✆✌

tmpnam function The synopsis of the function is



1 # include < stdio .h >
char * tmpnam ( char * s ) ;
✆✌
The tmpnam function generates a string that is a valid file name and that is not the name
of an existing file. A simple example is

# include < stdio .h >
2

/* Temporary file name pointer . */


4 char tmp_name [10];

6 int main () {

8 /* Assigne the name to name pointer . */


tmpnam ( tmp_name ) ;
10 if ( strlen ( tmp_name ) == 0) {
printf ( " Couldn ’ t get a work file name ...\ n " ) ;
12 exit (0) ;
} else {
14 printf ( " work file name is \"% s \". " , tmp_name ) ;
}
16 return 0;
}
✆✌
392 File & Data Structure


work file name is "/ tmp / t 76 c .0".
✆✌

Resize a File
truncate() function changes the size of the file. If the file has data of size n and the maker
offset is shorter than it, then everything after the marker position is made unavailable to
access. It returns 0 on success and -1 on error. The error EACCES returns if the file is a
directory or not writable. EINVAL, if length is negative. EFBIG, of the operation would
extend the file beyond the limits of the operating system. EIO, if a hardware I/O error
occurred. EPERM, if the file is in “append-only” or “immutable” mode and EINTR, if
the operation was interrupted by a signal.

File Pointer as Function Argument


In C, file pointers can be passed to a function as its argument. The syntax for file pointer
as function argument is given below:

1 void file_functio n ( FILE * < ptr_name >)
✆✌
In the following example, a file is opened in read mode in main function and the same
file pointer is passed to user defined function ‘print file’ as its argument. Inside the user
define function, contents of the file are read and print in output console.

1 # include < stdio .h >
# include < stdlib .h >
3

void print_file ( FILE *) ;


5

int main ( void ) {


7

FILE * fp = fopen ( " a . txt " , " r " ) ;


9 if (! fp ) {
perror ( " Unable to open file " ) ;
11 exit ( EXIT_FAILURE ) ;
}
13 print_file ( fp ) ;

15 return 0;
}
17

void print_file ( FILE * in ) {


19 char ch = 0;
while (! feof ( in ) ) {
21 ch = ( char ) getc ( in ) ;

23 if ( ferror ( in ) ) {
fputs ( " File error - Reading Operation " , stderr ) ;
25 exit ( EXIT_FAILURE ) ;
}
3.1. INPUT OUTPUT 393

27 if (! feof ( in ) ) {
putchar ( ch ) ;
29 }
}
31 return ;
}
✆✌

Low Level Input/Output


In this section, functions for performing low-level input/output operations on a file de-
scriptors are explained. Here, low level I/O functions uses file descriptor while high level
I/O functions uses streams. The low level descriptors are used in reading large binary
chunk from binary files or reading of whole file at once as done in mmap function. It is
used to perform operations rather than data transfer. The useful low level functions are
open(), fileno, close, read, write, lseek etc. These functions are declared in the header file
‘fcntl.h’.
open() This function is used to open a file descriptor for a file that is already existing
in the system. Its syntax is

int < file descriptor > = open ( < filename > , < mode >)
✆✌
This function creates a new file descriptor (an integer value) and returns it. Initially,
position of file descriptor is at the beginning of file. The mode tells how the file is open?
The mode values are O RDONLY, O WRONLY, O RDWR, O APPEND, O CREAT and
O TRUNC. Multiple modes can also be used by using binary ‘|’ operator. This function
returns the file descriptor value when it creates & opens a file descriptor successfully,
otherwise it returns ‘-1’ as error value.

1 # include < stdio .h >
# include < fcntl .h >
3

int main ( int argc , char * argv []) {


5 int fd ;
/* Read and write mode of file . */
7 if (( fd = open ( " a . pdf " , O_RDWR ) ) == -1) {
printf ( " Unable to open file .\ n " ) ;
9 return 1;
}
11 printf ( " File descriptor is :% d \ n " , fd ) ;
close ( fd ) ;
13 return 0;
}
✆✌

File descriptor is :3
✆✌
Modes O WRONLY, O CREAT and O TRUNC are used to create a new file and opening
of file descriptor.
394 File & Data Structure

close() This function is used to close a file descriptor. Its syntax is



1 int < state > = close ( < file descriptor >)
✆✌
When this function is called, the file descriptor is deallocated, any locked record is un-
locked and any unread data, if there, is discarded. It returns 0 on successful closing of
file descriptor and ‘-1’ in case of failure.

1 # include < stdio .h >
# include < fcntl .h >
3

int main ( int argc , char * argv []) {


5 int fd ;
/* Read and write mode of file . */
7 if (( fd = open ( " a . pdf " , O_RDWR ) ) == -1) {
printf ( " Unable to open file .\ n " ) ;
9 return 1;
}
11 printf ( " File descriptor is :% d \ n " , fd ) ;
/* Close the file descriptor . */
13 close ( fd ) ;
return 0;
15 }
✆✌

File descriptor is :3
✆✌

read() This function is used to read data from a file through a file descriptor. Its
syntax is

1 int < size of data read >
= read ( < file descriptor > , < buffer > , < size ( n ) >)
✆✌
This function reads data, equivalent to size ‘n’, from a file using file descriptor and copied
it to buffer. On successful read of data, it returns a number equivalent to bytes read
successfully through file descriptor. On failure it returns ‘-1’

# include < stdio .h >
2 # include < fcntl .h >

4 int main ( int argc , char * argv []) {


int fd ;
6 char * buff ;
if (( fd = open ( " a . pdf " , O_RDWR ) ) == -1) {
8 printf ( " Unable to open file .\ n " ) ;
return 1;
10 }
/* Read data */
12 int s = read ( fd , buff , 10) ;
printf ( " Read data is :% s \ n " , buff ) ;
14 close ( fd ) ;
3.1. INPUT OUTPUT 395

return 0;
16 }
✆✌

Read data is : aaaaaaaaaa
✆✌

write This function is used to write buffer data into a file through a file descriptor.
Its syntax is

1 int < size of data written >
= read ( < file descriptor > , < buffer > , < size ( n ) >)
✆✌
This function writes data of buffer, equivalent to size ‘n’, into a file using file descriptor.
The buffer data beyond the size ‘n’ is discarded, i.e. does not written into the file. On
successful wrote data into the file, it returns a number equivalent to number of data bytes
written successfully through file descriptor. On failure it returns ‘-1’.

# include < stdio .h >
2 # include < fcntl .h >

4 int main ( int argc , char * argv []) {


int fd ;
6 char * buff = " This is my file . " ;
if (( fd = open ( " a . pdf " , O_RDWR ) ) == -1) {
8 printf ( " Unable to open file .\ n " ) ;
return 1;
10 }
/* Write data */
12 int s = write ( fd , buff , 10) ;
printf ( " Size of written data is :% d \ n " , s ) ;
14 close ( fd ) ;
return 0;
16 }
✆✌

Size of written data is :10
✆✌

lseek () This function is used to change the position of file descriptor in a file for next
read or write. Its syntax is

1 off_t lseek ( < file descriptor > , < offset > , < from where >)
✆✌
The ‘offset’ is the position value that may be changed for file descriptor either from the
beginning of the file, or from the current position of the file or from the end of file. The
values for third argument are SEEK SET, SEEK CUR or SEEK END. The return value
of lseek function is either off t or off64 t as the case may be. On failure it returns ‘-1’.

1 # include < stdio .h >
# include < fcntl .h >
3
396 File & Data Structure

int main ( int argc , char * argv []) {


5 int fd ;
if (( fd = open ( " a . pdf " , O_RDONLY ) ) == -1) {
7 printf ( " Unable to open file .\ n " ) ;
return 1;
9 }
char * buff ;
11 read ( fd , buff , 10) ;
printf ( " Read data is :% s \ n " , buff ) ;
13 /* Set file descriptor to new position */
lseek ( fd , 10 , SEEK_CUR ) ;
15 read ( fd , buff , 10) ;
printf ( " Read data is :% s \ n " , buff ) ;
17 close ( fd ) ;
return 0;
19 }
✆✌

Read data is : This is my
Read data is : aaaaaaaaaa
✆✌

fdopen() This function is used to open a stream for a file descriptor. Its syntax is

FILE * < new stream >
2 = fdopen ( < file descriptor > , < mode >)
✆✌
The mode values are any one of the values ‘w’, ‘w+’, ‘r’, ‘r+’ and others associated with
fopen function. On successful it returns stream pointer and on failure it returns null
pointer. Mixing of I/O functions exclusively used with streams and I/O functions exclu-
sively defined for file descriptor is dangerous. Therefore, it should be checked whether a
file descriptor is associated with stream pointer or not by using fileno function as given
in following syntax.

int < file descriptor > = fileno ( < stream >) ;
✆✌
fileno returns the file descriptor associated with the stream. If an error is detected or if
stream does not have a file descriptor, fileno returns ‘-1’.

1 # include < stdio .h >
# include < fcntl .h >
3

int main ( int argc , char * argv []) {


5 int fd ;
FILE * f ;
7 char * buff ;
if (( fd = open ( " a . pdf " , O_RDONLY ) ) == -1) {
9 printf ( " Unable to open file .\ n " ) ;
return 1;
11 }
/* Link file descriptor to stream */
13 f = fdopen ( fd , " r " ) ;
3.2. SYMBOL TABLE 397

/* Get file descriptor linked to stream */


15 int fdn = fileno ( f ) ;
printf ( " Associated file descriptor is :% d \ n " , fdn ) ;
17 fread ( buff , sizeof ( char ) , 10 , f ) ;
printf ( " Read data is :% s \ n " , buff ) ;
19 close ( fd ) ;
return 0;
21 }
✆✌

Associated file descriptor is :3
Read data is : This is my
✆✌

3.2 Symbol Table


Symbol Table is a data structure that is created and maintained by the compiler in order
to keep track about scope and binding names of a variable, its instances, function names,
classes, objects, etc. A new table is created to store entries, like tokens, attribute type of
variable, scope of variable, dimension of variable, line of reference, use, etc. This available
information is used to verify expression, code optimization and target code generation by
compilers. Entry stored in symbol table are variable name, function name, literals, labels,
addresses etc.

3.3 Data Structures


A data structure (struct ) contains multiple pieces of data. Each piece of data (called a
“member”) can be accessed by using a group of instance of structure, followed by a ‘.’ (ie
dot), then the name of the member (another way to access a member is using the member
operator ‘−>’ for pointers.). The member variables of data structure can be of any data
type or can be an array or a pointer.

3.3.1 Structures
A data structure contains multiple pieces of data. To collect data, variables (structure
elements) of appropriate data type are used. A function can not be an element of the
structure. Structure in C is declared with struct keyword. Skeletal of the struct keyword
is shown below:

struct < structure_name >{
2 int < int_member >;
double < double_member >;
4 char < string_member [25] >;
} < structure_alias_n ame >;
✆✌
‘structure alias name’ is instance of ‘structure name’. We can omit it from the end of the
struct declaration and it may be declared later as shown below:
398 File & Data Structure


1 struct < structure_name > < structure_alias_nam e >;
✆✌
It is common practice to make a type synonym so we don’t have to type

1 struct < structure_name >
✆✌
all the time when this structure is required. The struct itself has no name (by the absence
of a name on the first line), but it is aliased as ‘structure name’. We can use

1 < structure_name > < structure_alias_na me >;
✆✌
to create structure instances as and when required. We can add data into structure or
read data from structure by using ‘dot’ symbol (direct member access).

1 struct student {
int id ;
3 char * name ;
float perc ;
5 } st ;
st . id =1; /* Use dot symbol between instance *
7 * name and structure element . */
✆✌
After creating an instance of structure, instance reserves the memory bytes equal to the
sum of size of all members. In a C structure, a string element declared as char *s does
not contains the string itself. It contains the address where string is stored. This is why,
the size of char *s element of the structure is 4 bytes only.

1 # include < stdio .h >

3 struct myStruct {
char * s ;
5 };
int main () {
7 struct myStruct st ;
printf ( " Size of st is % d bytes . " , ( int ) sizeof ( st ) ) ;
9 return 0;
}
✆✌

Size of st is 4 bytes .
✆✌
If a structure contains a pointer member then it stores the memory address of those
values/variables to whom it is pointing. For example, in the following structure:

1 struct st {
int i ;
3 char * s ;
} myS ;
✆✌
3.3. DATA STRUCTURES 399

In above structure, there are two members. First in ‘i’ which is integer type. This variable
holds value itself. For illustration purpose, let it holds value 1224527 in decimal form.
The second member is a pointer of string contains alphabets from A to I. The pointer
variable does not holds value itself but it holds the address of first string character as
shown in the following figure.

myS
int i char *s
0×12AF 4F 0×80
0×50 0×51 0×52 0×53 0×50 0×51 0×52 0×53

A B C D E F G H I \0
0×80 0×81 0×82 0×83 0×84 0×85 0×86 0×87 0×88 0×89

Though total data size is 14 bytes long (4 bytes of integer and 10 bytes of string) yet
the size of ‘myS’ is 8 bytes. This is because, four bytes is used by int data type variable
and four bytes are used by pointer variable. If string element, declared as char s[¡n¿],
contains the string of suitable size ‘n’ itself. Example for fixed string elements within the
structure.

# include < stdio .h >
2

struct myStruct {
4 char s [10];
};
6 int main () {
struct myStruct st ;
8 printf ( " Size of st is % d bytes . " , ( int ) sizeof ( st ) ) ;
return 0;
10 }
✆✌

Size of st is 10 bytes .
✆✌
See the figure given below:

st

id name perc

After creating an instance of structure, instance reserves the memory space (N ) in


bytes equal to or greater than the sum of bytes reserved by the structure members, where
N is perfect multiple of size of all member data types. The size calculation is done as
given in following examples.
400 File & Data Structure


1 struct s {
int id1 ; // 4 bytes for data
3 int id2 ; // 4 bytes for data
}; // total size will be equal to sum of all
5 // bytes , upward rounded off to , multiple
// to size of largest structure member .
✆✌

# include < stdio .h >
2

struct s {
4 int id1 ;
int id2 ;
6 }; // Total 8 bytes rounded up to
// 4*2=8 bytes is size of s
8

int main () {
10 printf ( " Size of Structure s in bytes is " ) ;
printf ( " % d .\ n " , sizeof ( struct s ) ) ;
12 return 0;
}
✆✌

Size of Structure s in bytes is 8
✆✌
Here, sum of memory bytes calculated from structure members, is rounded off upward
so that it is perfect multiple of the largest data type member of that structure. This is
because, number of elements (n) in an array is given by

Sum of Bytes
n=
sizeof (data type)

Where n is an integer. If there are multiple datatypes as in the case of a structure, if bytes
are not multiple of all member datatypes’ size, then n becomes fraction. This rounding
off is done to make structure operation easy. Take another case:

1 struct s {
int id1 ; // 4 bytes for data
3 double id2 ; // 8 bytes for data
}; // total size will be equal to sum of all
5 // bytes , upward rounded off to , multiple
// to size of largest structure member .
✆✌

# include < stdio .h >
2

struct s {
4 int id1 ;
double id2 ;
6 }; // Total 12 bytes rounded up to
// 8*2=16 bytes is size of s
3.3. DATA STRUCTURES 401

int main () {
10 printf ( " Size of Structure s in bytes is " ) ;
printf ( " % d .\ n " , sizeof ( struct s ) ) ;
12 return 0;
}
✆✌

Size of Structure s in bytes is 16
✆✌

1 struct s {
int id1 ; // 4 bytes for data
3 double * id2 ; // 4 bytes for address
}; // total size will be equal to sum of all
5 // bytes , upward rounded off to , multiple
// to size of largest structure member .
✆✌

# include < stdio .h >
2

struct s {
4 int id1 ;
double * id2 ;
6 }; // Total 8 bytes rounded up to
// 4*2=8 bytes is size of s
8

int main () {
10 printf ( " Size of Structure s in bytes is " ) ;
printf ( " % d .\ n " , sizeof ( struct s ) ) ;
12 return 0;
}
✆✌

Size of Structure s in bytes is 8
✆✌
Next example

1 struct s {
int id1 ; // 4 bytes for data
3 char id2 ; // 1 byte for data
}; // total size will be equal to sum of all
5 // bytes , upward rounded off to , multiple
// to size of largest structure member .
✆✌

# include < stdio .h >
2

struct s {
4 int id1 ;
char id2 ;
6 }; // Total 5 bytes rounded up to
// 4*2=8 bytes is size of s
402 File & Data Structure

int main () {
10 printf ( " Size of Structure s in bytes is " ) ;
printf ( " % d .\ n " , sizeof ( struct s ) ) ;
12 return 0;
}
✆✌

Size of Structure s in bytes is 8
✆✌
Next example

1 struct s {
char id1 ; // 1 byte for data
3 char id2 ; // 1 byte for data
}; // total size will be equal to sum of all
5 // bytes , upward rounded off to , multiple
// to size of largest structure member .
✆✌

# include < stdio .h >
2

struct s {
4 char id1 ;
char id2 ;
6 }; // Total 2 bytes rounded up to
// 1*2=2 bytes is size of s
8

int main () {
10 printf ( " Size of Structure s in bytes is " ) ;
printf ( " % d .\ n " , sizeof ( struct s ) ) ;
12 return 0;
}
✆✌

Size of Structure s in bytes is 2
✆✌
Next example

1 struct s {
char * id1 ; // 4 bytes for address
3 char * id2 ; // 4 bytes for address
}; // total size will be equal to sum of all
5 // bytes , upward rounded off to , multiple
// to size of largest structure member .
✆✌

# include < stdio .h >
2

struct s {
4 char * id1 ;
char * id2 ;
6 }; // Total 8 bytes rounded up to
3.3. DATA STRUCTURES 403

// 4*2=8 bytes is size of s


8

int main () {
10 printf ( " Size of Structure s in bytes is " ) ;
printf ( " % d .\ n " , sizeof ( struct s ) ) ;
12 return 0;
}
✆✌

Size of Structure s in bytes is 8
✆✌
Next example

1 struct s {
char id1 [5]; // 5 bytes for data
3 char id2 ; // 1 byte for data
}; // total size will be equal to sum of all
5 // bytes , upward rounded off to , multiple
// to size of largest structure member .
✆✌

# include < stdio .h >
2

struct s {
4 char id1 [5];
char id2 ;
6 }; // Total 6 bytes rounded up to
// 1*6=6 bytes is size of s
8

int main () {
10 printf ( " Size of Structure s in bytes is " ) ;
printf ( " % d .\ n " , sizeof ( struct s ) ) ;
12 return 0;
}
✆✌

Size of Structure s in bytes is 6
✆✌
Next example

1 struct s {
char id1 [5]; // 5 bytes for data
3 char * id2 ; // 4 bytes for address
}; // total size will be equal to sum of all
5 // bytes , upward rounded off to , multiple
// to size of largest structure member .
✆✌

# include < stdio .h >
2

struct s {
4 char id1 [5];
char * id2 ;
404 File & Data Structure

6 }; // Total 9 bytes rounded up to


// 4*3=12 bytes is size of s
8

10 int main () {
printf ( " Size of Structure s in bytes is " ) ;
12 printf ( " % d .\ n " , sizeof ( struct s ) ) ;
return 0;
14 }
✆✌

Size of Structure s in bytes is 12
✆✌
Next example

1 struct s {
char id1 [5]; // 5 bytes for data
3 double id2 ; // 8 bytes for address
}; // total size will be equal to sum of all
5 // bytes , upward rounded off to , multiple
// to size of largest structure member .
✆✌

# include < stdio .h >
2

struct s {
4 char id1 [5];
double id2 ;
6 }; // Total 13 bytes rounded up to
// 8*2=16 bytes is size of s
8

int main () {
10 printf ( " Size of Structure s in bytes is " ) ;
printf ( " % d .\ n " , sizeof ( struct s ) ) ;
12 return 0;
}
✆✌

Size of Structure s in bytes is 16
✆✌
Next example

1 struct s {
char id0 [10]; // 10 bytes for data
3 char id1 [10]; // 10 bytes for data
char id2 [11]; // 11 bytes for data
5 int id3 [2]; // 8 bytes for data
int id4 [5]; // 20 bytes for data
7 double id5 ; // 8 bytes for address
}; // total size will be equal to sum of all
9 // bytes , upward rounded off to , multiple
// to size of largest structure member .
✆✌
3.3. DATA STRUCTURES 405


# include < stdio .h >
2

struct s {
4 char id0 [10];
char id1 [10];
6 char id2 [11];
int id3 [2];
8 int id4 [5];
double id5 ;
10 }; // Total 67 bytes rounded up to
// 8*9=72 bytes is size of s
12

int main () {
14 printf ( " Size of Structure s in bytes is " ) ;
printf ( " % d .\ n " , sizeof ( struct s ) ) ;
16 return 0;
}
✆✌

Size of Structure s in bytes is 72
✆✌
Here is working example of struct function:

1 # include < stdio .h >

3 struct student {
int id ;
5 char * name ;
float perc ;
7 } st , st1 , st2 ;

9 int main () {
st . id = 1;
11 st1 . name = " Arun Umrao " ;
st2 . perc = 90.5;
13 printf ( " Id is : % d \ n " , st . id ) ;
printf ( " Name is : % s \ n " , st1 . name ) ;
15 printf ( " Percentage is : % f \ n " , st2 . perc ) ;
return 0;
17 }
✆✌

Id is : 1
Name is : Arun Umrao
Percentage is : 90.500000
✆✌
Another simple example is given below.

1 # include < stdio .h >

3 struct data {
406 File & Data Structure

int val ;
5 float b ;
};
7

int main ( void ) {


9 struct data s ;
s . val = 12;
11 s . b = 3.14159;
printf ( " The val field in s is : % d \ n " , s . val ) ;
13 return 0;
}
✆✌

The val field in s is : 12
✆✌
Pointer can be also used in structure. An instance of a structure ‘data’ using a pointer is
declared as

1 data * < variable >;
✆✌
Member values of the structure declared with pointer are initialized or accessed by using
operator −> (indirect member access). See the following syntax, in which a structure
‘Func’ is declared by using a pointer and its member values are set by using operator −>.

1 struct Func {
int val ;
3 float fl ;
};
5 struct Func * b ;
b - > val = 3491;
✆✌

st st++

val fl

A working example is

# include < stdio .h >
2

struct Func {
4 int val ;
float fl ;
6 };

8 int main ( void ) {


/* Func struct required for pointer */
10 struct Func a ;
/* this is a pointer to a struct Func */
3.3. DATA STRUCTURES 407

12 struct Func * b ;
b - > val = 3491;
14 printf ( " The value of b is % d . " , b - > val ) ;
return 0;
16 }
✆✌

The value of b is 3491.
✆✌
A struct data can also be passed to a function by using address of procedure. See the
example below in which data struct is passed to function ‘Plantation’.

1 # include < stdio .h >

3 /* Data structure */
struct Data {
5 int Trees ;
int Plants ;
7 };

9 /* function Plantation with data structure as pointer */


void Plantation ( struct Data * f ) {
11 f - > Trees = 10;
f - > Plants = 20;
13 }

15 int main ( void ) {


/* Struct data structure */
17 struct Data Bio ;
/* Pass address ‘ Bio ’ into struct ‘ Data ’ as pointer */
19 Plantation (& Bio ) ;
printf ( " Trees : % d \ n " , Bio . Trees ) ; /* prints "10" */
21 printf ( " Plants : % d \ n " , Bio . Plants ) ; /* prints "20" */
return 0;
23 }
✆✌

Trees : 10
Plants : 20
✆✌
A constant pointer, once holds an address cannot change to the new address. It means a
constant pointer, if already pointing to an address, cannot point to a new address.

# include < stdio .h >
2

int main ( void ) {


4 char ch = ’A ’;
char cH = ’B ’;
6

char * const ptr = & ch ; // A constant pointer


8 ptr = & cH ; // Illegal way of pointer .
408 File & Data Structure

10 return 0;
}
✆✌
In case of pointer to structure, if the things on the left of the ‘.’ (dot) or ‘−>’ operator
is qualified (with const or volatile) then the result is also has those qualifiers associated
with it. In the following example, when the pointer points to a qualified type the result
got is also qualified.

1 # include < stdio .h >
# include < stdlib .h >
3

struct myStruct {
5 int i ;
};
7

main () {
9 /* Initialisat io n of structures . */
struct myStruct * Ptr , s_item ;
11 /* Initialisat io n of structures of constant qualifier . */
const struct myStruct * s_Ptr ;
13 /* Set the item value . */
s_item . i = 1; /* OK */
15 /* Assigning new pointer . */
Ptr = & s_item ;
17 Ptr - > i += 2; /* OK */
/* Constant qualified pointer . */
19 s_Ptr = & s_item ;
s_Ptr - > i = 0; /* Not OK as points to constant type qualifier . */
21

exit ( EXIT_SUCCESS ) ;
23 }
✆✌
A structure can also be initialized at the starting of program if structure is defined as

1 struct employee {
int no ;
3 int sex ;
int age ;
5 };
struct employee EmpNo ={ < int > , < int > , < int >};
✆✌
The following example clears the initialization of the structure.

# include < stdio .h >
2

struct employee {
4 int no ;
int sex ;
6 int age ;
};
8
3.3. DATA STRUCTURES 409

int main () {
10 /* Structure declared and initialized . */
struct employee EmpNo ={10 ,1 ,15};
12 printf ( " % d \ t % d \ t % d \ n " , EmpNo . no , EmpNo . sex , EmpNo . age ) ;
return 0;
14 }
✆✌
A self referential structures has same member name as its name is. See the following
example.

struct myStruct {
2 int i ;
char j [10];
4 struct myStruct * myStructRef ; // Legal
};
✆✌
In case of pointer type self referral, size of a pointer to a structure is known to compiler
even before the size of the structure has been determined. Note that the self referential
structure should be a pointer not a structure. For example, at above structure, ‘myS-
tructRef’ is pointer not a structure itself. If it is a structure, then it will contain member
‘myStructRef’ recursively (member within member).

1 struct myStruct {
int i ;
3 char j [10];
struct myStruct myStructRef ; // Illegal
5 };
✆✌
Following type of self referral is also illegal.

1 typedef struct {
int i ;
3 char j [10];
myStructAlia s * myStructRef ; // Illegal
5 } myStructAlias ;
✆✌
The reason is that the type name is defined after the declaration of structure, therefore,
line

1 struct myStruct * myStructRef ; // Illegal
✆✌
will show error as self referral structure is declared before the type name is defined. The
legal form is given below:

1 typedef struct myStruct {
int i ;
3 char j [10];
struct myStruct * myStructRef ; // Legal
5 } myStructAlias ;
✆✌
410 File & Data Structure

Nested Structure
Structure within structure i.e. nested structure can also be declared by using either normal
variable or pointer. In following example, a nested structure is declared and declared by
simple variable. From structural inheritance, inner structure is accessible from instances
of outer structure.

1 # include < stdio .h >

3 int main () {

5 /* date structure */
struct date {
7 int day ;
int month ;
9 int year ;
};
11

/* variety structure */
13 struct variety { /* Upper level structure */
char * name ;
15

/* Date is Lower level nested structure . it is *


17 * declared as normal structure . Elements of *
* date structure are accessed by dot (.) . */
19 struct date date ;
} tr ; /* Structure declared as normal variable . *
21 * Elements can be accessed by (.) symbol . */

23 /* Accessing structure elements by using synopsis like


* up_level_s tr uc t (.) up_level_elem
25 * or
* up_level_s tr uc t (.) low_level_s t ru ct (.) low_level_e le m */
27 tr . name = " A " ;
tr . date . day = 10;
29 printf ( " Name : % s \ n " , tr . name ) ;
printf ( " day : % d \ n " , tr . date . day ) ;
31 return 0;
}
✆✌

Name : A
day : 10
✆✌
In simple variable type declaration of structure, elements are accesses by using dot (.).
Using of pointer symbol (−>) throws the errors.

# include < stdio .h >
2

int main () {
4

/* date structure */
3.3. DATA STRUCTURES 411

6 struct date {
int day ;
8 int month ;
int year ;
10 };

12 /* variety structure */
struct variety { /* Upper level structure */
14 char * name ;

16 /* Date is Lower level nested structure . it is *


* declared as normal structure . Elements of *
18 * date structure are accessed by dot (.) . */
struct date date ;
20 } tr ; /* Structure declared as normal variable . *
* Elements can be accessed by (.) symbol . */
22

/* Accessing structure elements by using synopsis like


24 * up_level_s tr uc t (.) up_level_elem
* or
26 * up_level_s tr uc t (.) low_level_s t ru ct (.) low_level_e le m */
tr . name = " A " ;
28 tr . date . day = 10;

30 /* Following line show errors . Reason is that we are trying *


* to access the element by pointer symbol ( - >) even though *
32 * the structure ‘ tr ’ is declared here as normal variable . */
tr - > date . month = 11;
34 printf ( " Name : % s \ n " , tr . name ) ;
printf ( " day : % d \ n " , tr . date . day ) ;
36 return 0;
}
✆✌
Other-way to assign a structure inside another struct is pointer method. In pointer
method, elements are accessed by using pointer symbol (−>) and dot (.).

1 # include < stdio .h >

3 int main () {

5 /* date structure */
struct date {
7 int day ;
int month ;
9 int year ;
};
11

/* variety structure */
13 struct variety { /* Upper level structure */
char * name ;
15
412 File & Data Structure

/* Date is Lower level nested structure . it is *


17 * declared as normal structure . Elements of *
* date structure are accessed by dot (.) . */
19 struct date date ;
} * tr ; /* Structure declared as pointer variable . *
21 * Elements can be accessed by ( - >) symbol . */

23 /* Accessing structure elements by using synopsis like


* up_level_s tr uc t ( - >) up_level_elem
25 * or
* up_level_s tr uc t ( - >) low_level_s t ru ct (.) low_level_e le m */
27 tr - > name = " A " ;
tr - > date . day = 10;
29 printf ( " Name : % s \ n " , tr - > name ) ;
printf ( " day : % d \ n " , tr - > date . day ) ;
31 return 0;
}
✆✌

Name : A
day : 10
✆✌
Again, indirect membership operator or structure pointer operator (−>) is not used in
the level or element of the structure declared as normal variable.

# include < stdio .h >
2

int main () {
4

/* date structure */
6 struct date {
int day ;
8 int month ;
int year ;
10 };

12 /* variety structure */
struct variety { /* upper level structure */
14 char * name ;

16 /* Date is Lower level nested structure . it is *


* declared as normal structure . Elements of *
18 * date structure are accessed by dot (.) . */
struct date date ;
20 } * tr ; /* Structure declared as pointer variable .*
* Elements are accessed by ( - >) symbol . */
22

/* Following lines show errors . We are trying *


24 * to access the elements of structure ‘ date ’ *
* by pointer symbol ( - >) while the structure *
26 * ‘ date ’ is declared here as normal variable . */
tr - > date - > day = 10;
3.3. DATA STRUCTURES 413

28 tr . date - > day = 10;


return 0;
30 }
✆✌
But the lower level elements can also be accessed by using pointer symbol (−>) if lower
level structure is also declared as pointer level.

# include < stdio .h >
2

int main () {
4

/* date structure */
6 struct date {
int day ;
8 int month ;
int year ;
10 };

12 /* variety structure */
struct variety { /* upper level structure */
14 char * name ;
/* Date is Lower level nested structure . it is *
16 * declared as pointer structure . Elements of *
* date structure are accessed by dot ( - >) . */
18 struct date * date ;
} * tr ; /* Structure declared as pointer variable . *
20 * Elements can be accessed by ( - >) symbol . */

22 /* Accessing structure elements by using synopsis like


* up_level_s tr uc t ( - >) up_level_elem
24 * or
* up_level_s tr uc t ( - >) low_level_s t ru ct ( - >) low_level_e le m */
26 tr - > date - > day = 10;
tr - > date - > month = 10;
28 printf ( " Day : % d \ n " , tr - > date - > day ) ;
printf ( " Month : % d \ n " , tr - > date - > month ) ;
30 return 0;
}
✆✌

Day : 10
Month : 10
✆✌
In above examples, it is clarified that, elements of structures declared as variable type are
accessed by using dot (.) and elements of structure declared as pointer type are accessed
by using indirect membership operator or structure pointer operator (−>).

# include < stdio .h >
2

int main () {
4
414 File & Data Structure

/* date structure */
6 struct date {
int day ;
8 int month ;
int year ;
10 };

12 /* variety structure */
struct variety { /* up_level_str u ct ( uls ) */
14 char * name ;

16 /* Date is Lower level nested structure . it is *


* declared as pointer structure . Elements of *
18 * date structure are accessed by dot ( - >) . */
struct date * date ;
20 } tr ; /* Structure declared as normal variable .*
* Elements can be accessed by dot (.) . */
22

/* Accessing structure elements by using synopsis like


24 * up_level_s tr uc t (.) up_level_elem
* or
26 * up_level_s tr uc t (.) low_level_s tr u ct ( - >) low_level_e le m */
tr . date - > day = 10;
28 tr . date - > month = 10;
printf ( " Day : % d \ n " , tr . date - > day ) ;
30 printf ( " Month : % d \ n " , tr . date - > month ) ;
return 0;
32 }
✆✌

Day : 10
Month : 10
✆✌

Structure As Arguments
Like other variables, file pointers and function pointers, a structure can also be passed
to a function as its argument. The method of passing a structure to a function is given
below:

int myFunc ( struct < structure name > < local var >) ;
✆✌
In the following example, structure ‘g len’ is passed to function ‘sum’. Numerical values
of structure elements are get summed and returned to the caller. shown in the example
below:

1 # include < stdio .h >
# define TREE_NUM 50
3

/* Structure for garden tree length . */


5 struct g_len {
3.3. DATA STRUCTURES 415

char gardens [ TREE_NUM ];


7 double t_len_1 ;
double t_len_2 ;
9 };

11 /* Structure passed to the function . */


double sum ( struct g_len val ) {
13 return ( val . t_len_1 + val . t_len_2 ) ;
}
15

int main ( void ) {


17 /* Initialized the structure . */
struct g_len sbi = {
19 " G DELHI " ,
6524.12 ,
21 9458.87
};
23 printf ( " Tree length is %.2 fm .\ n " , sum ( sbi ) ) ;
return 0;
25 }
✆✌

Tree length is 15982.99 m .
✆✌
Structure data allows us to write data of desired size into text or binary file. To write
struct data into a file we use fwrite function as

1 FILE * fp ; /* A file stream */
struct TreeData { /* Structure TreeData */
3 int x ;
int y ;
5 }
/* Create TreeData space . */
7 struct TreeData * td = malloc ( sizeof ( struct TreeData ) ) ;
/* Write structure data into file . */
9 fwrite ( td , sizeof ( struct TreeData ) , 1 , fp ) ;
✆✌
Here is complete example:

1 # include < stdio .h >

3 struct TreeData {
int x_old ;
5 int y_old ;
int x_new ;
7 int y_new ;
int val ;
9 };

11 void insert ( char *f , int x_old , int y_old , int val ) {


struct TreeData * td = malloc ( sizeof ( struct TreeData ) ) ;
13 FILE * fp ;
416 File & Data Structure

int xnew ;
15 int ynew ;
if ( td - > x_new == 0 || td - > y_new == 0) {
17 td - > x_new = 0;
td - > y_new = 0;
19 } else {
xnew = td - > x_new ;
21 ynew = td - > y_new ;
}
23 td - > x_old = x_old ;
td - > y_old = y_old ;
25 td - > val = val ;
fp = fopen (f , " wb " ) ;
27 fwrite ( td , sizeof ( struct TreeData ) , 1 , fp ) ;
fclose ( fp ) ;
29 td - > x_new = xnew + 1;
td - > y_new = ynew + 1;
31 }

33 int main () {
char * f = " TreeNode . txt " ;
35 struct TreeData myNode ;
insert (f , 0 , 0 , 95) ;
37 return 0;
}
✆✌

Multi-Dimensional Struct
Technically a multidimensional structure can not be declared. But tricking methods
can be used to store a multidimensional data with help of structure. For example, a
two dimensional values can be stored via structure if we declared a structure with two
elements. One for storing data of one dimension and other for storing data of second
dimension. Yet a structure can be declared as an array. A structure capable of storing
two dimensional data is declared as given below:

struct myStruct { /* Structure with 2 elements */
2 int i ; /* First element of 4 bytes size */
int j ; /* Second element of 4 bytes size */
4 };
struct myStruct s [2]; /* Initialize 2 - dim structure for *
6 * storing two elements of an array */
✆✌
The memory size required to store this structure is equal to the product of number of
dimension of structure and total size of structure elements. In above syntax, size of
structure is (4 + 4) × 2 = 16 bytes. See the example below:

# include < stdio .h >
2

int main () {
4
3.3. DATA STRUCTURES 417

struct twoDimStruct {
6 int x ;
int y ;
8 };
struct twoDimStruct s [10];
10 printf ( " Size of Structure is % d bytes .\ n " , sizeof ( s ) ) ;
return 0;
12 }
✆✌

Size of Structure is 80 bytes .
✆✌
Here, structure creates space for data storage, hence memory allocation is not required.
But we can use dynamically allocated memory as shown below:

1 # include < stdio .h >

3 int main () {
int i ;
5

typedef struct {
7 int x ;
int y ;
9 } mStruc ;
/* Allocate memory space for all *
11 * columns of size (4+4) *10 bytes . */
mStruc ** s = ( mStruc **) malloc (10 * sizeof ( mStruc *) ) ;
13 for ( i = 0; i < 10; i ++) {
/* Allocate memory space for each *
15 * rows as group of above columns . */
s [ i ] = ( mStruc *) malloc (10 * sizeof ( mStruc ) ) ;
17 }
return 0;
19 }
✆✌
Assume a four element structure as syntaxed below:

1 typedef struct {
int x ; /* 4 bytes long */
3 char c ; /* 1 byte long */
int y ; /* 4 bytes long */
5 char k ; /* 1 byte long */
} e;
7 /* ** s points to memory for 10 elements *
* where each element is 10 bytes long .*
9 * it forms columns of the each row . */
e ** s = ( e **) malloc (10 * sizeof ( e *) ) ;
11 for ( i = 0; i < 10; i ++) {
/* Allocate memory space for each *
13 * rows as group of above columns . */
s [ i ] = ( e *) malloc (10 * sizeof ( e ) ) ;
15 }
✆✌
418 File & Data Structure

The memory space is created for a structure array of 10 × 10. The memory space is
reserved with help of malloc command. The memory space is represented by:

e[0] e[1]
c k c k
x x
n n n n c n n n n c n n n n c n n n n c
y y
∗∗
s
s[0]

We can store value for each structure and retrieve it as and when required. See the
example below:

1 # include < stdio .h >

3 int main () {

5 struct twoDimStruct {
int x ;
7 int y ;
};
9 struct twoDimStruct s [10];
s [1]. x = 5;
11 s [1]. y = 10;
s [3]. y = 25;
13 printf ( " s [1]. x = % d .\ n " , s [1]. x ) ;
printf ( " s [1]. y = % d .\ n " , s [1]. y ) ;
15 printf ( " s [3]. x = % d .\ n " , s [3]. x ) ;
printf ( " s [3]. y = % d .\ n " , s [3]. y ) ;
17 return 0;
}
✆✌

s [1]. x = 5.
s [1]. y = 10.
s [3]. x = 1.
s [3]. y = 25.
✆✌
When structure is declared as array, if reserves memory equal to the product of size of
structure and structure array size. For example, the statement

struct twoDimStruct s [10];
✆✌
memory space for ten struct elements are reserved. Total size of instance ‘s’ is (4+4)×10 =
80 bytes. If structure is declared as

1 struct twoDimStruct s [10][3];
✆✌
then it has ten rows and three columns in which each element has structure elements ‘x’
and ‘y’. See the example given below:
3.3. DATA STRUCTURES 419


1 # include < stdio .h >

3 int main () {

5 struct twoDimStruct {
int x ;
7 int y ;
};
9 struct twoDimStruct s [4][3];
s [1][0]. x = 5;
11 s [1][0]. y = 6;
s [1][1]. x = 7;
13 s [1][1]. y = 8;
s [1][2]. x = 9;
15 s [1][2]. y = 10;
printf ( " % d \ t % d \ t " , s [1][0]. x , s [1][0]. y ) ;
17 printf ( " % d \ t % d \ t " , s [1][1]. x , s [1][1]. y ) ;
printf ( " % d \ t % d \ n " , s [1][2]. x , s [1][2]. y ) ;
19 return 0;
}
✆✌

5 6 7 8 9 10
✆✌
The memory arrangement of the two dimensional structure is shown in the following
figure.

x00 y00 x01 y01 x02 y02

x10 y10 x11 y11 x12 y12

x20 y20 x21 y21 x22 y22

x30 y30 x31 y31 x32 y32

The address of the structure elements are retrieved in the following example to check
the order of elements in the memory.

1 # include < stdio .h >

3 int main () {

5 struct twoDimStruct {
int x ;
7 int y ;
};
9 struct twoDimStruct s [4][3];
s [1][0]. x = 5;
11 s [1][0]. y = 6;
s [1][1]. x = 7;
420 File & Data Structure

13 s [1][1]. y = 8;
s [1][2]. x = 9;
15 s [1][2]. y = 10;
printf ( " % x \ t % x \ n " , &( s [1][0]. x ) , &( s [1][0]. y ) ) ;
17 printf ( " % x \ t % x \ n " , &( s [1][1]. x ) , &( s [1][1]. y ) ) ;
printf ( " % x \ t % x \ n " , &( s [1][2]. x ) , &( s [1][2]. y ) ) ;
19 return 0;
}
✆✌

c 280 b 9 b 8 c 280 b 9 bc
c 280 b 9 c 0 c 280 b 9 c 4
c 280 b 9 c 8 c 280 b 9 cc
✆✌
A structure can be returned from a function but an array can not be so. See the following
example, in which a copy of the local, automatically allocated structure is made on return
and then the local copy is destroyed.

1 # include < stdio .h >

3 typedef struct {
double square , cube ;
5 } A;

7 A getAns ( double in ) {
A out = {
9 . square = in * in ,
. cube = in * in * in
11 };
return out ;
13 }

15 int main () {
A res = getAns (3) ;
17 printf ( " Result : % g \ t % g \ t \ n " , res . square , res . cube ) ;
return 0;
19 }
✆✌

Result : 9 27
✆✌

Return Structure from Function


We may return structure from inside of a function. Note that the address of returned
structure is address of first member of the structure. Value of first member of structure is
printed in output console with warning. If there are multiple members in a structure then
it is good practice to call member of the structure rather than calling whole structure.
See the example below:

1 # include < stdio .h >
3.3. DATA STRUCTURES 421

3 struct st {
int i ; /* First element */
5 int j ; /* Second element */
};
7

struct st myF ( int x ) {


9 struct st s ; /* Create structure object */
s . i = x ; /* Set value to first element */
11 s . j = 2 * x ; /* Set value to second element */
return s ; /* Return structure address */
13 }

15 int main () {

17 /* Prints first element of the structure */


printf ( " % d \ n " , myF (20) . i ) ;
19 /* Prints second element of the structure */
printf ( " % d \ n " , myF (20) . j ) ;
21 return 0;
}
✆✌

20
40
✆✌

3.3.2 Enumerate
In C, enumerations are created by explicit definitions, which use the enum keyword and
are reminiscent of struct and union definitions. See example below.

# include < stdio .h >
2

enum {
4 /* 0 */ /* 1 */ /* 2 */
TRUE , FALSE , NO
6 } b = NO ;

8 int main ( int argc , char ** argv ) {


printf ( " bool : % d \ n " , b ) ;
10

return 0;
12 }
✆✌

bool : 2
✆✌
C also allows the programmer to choose the values of the enumeration constants explicitly,
even without type.
422 File & Data Structure


1 # include < stdio .h >

3 enum {
TRUE = 0 , FALSE = 1 , NO = 10
5 } b = NO ;

7 int main ( int argc , char ** argv ) {


printf ( " bool : % d \ n " , b ) ;
9

return 0;
11 }
✆✌

bool : 10
✆✌
In enumerate the values are assigned successively. If any enum key is set to a specific
value then next enum key has value one larger than its preceding enum key.

1 # include < stdio .h >

3 int main () {

5 enum COLORS {
BLUE , /* Index value 0 */
7 GREEN = 3 , /* Index value 3 */
YELLOW , /* Index value 4 */
9 RED = 2 , /* Index value 2 */
BLACK /* Index value 3 */
11 };
printf ( " The colors are :\ n " ) ;
13 printf ( " % d \ n " , BLUE ) ; /* 0 */
printf ( " % d \ n " , YELLOW ) ; /* 4 */
15 printf ( " % d \ n " , BLACK ) ; /* 3 */
return 0;
17 }
✆✌

The colors are :
0
4
3
✆✌

3.3.3 Unions
The definition of a union is similar to that of a struct. The difference between the two
is that in a struct, the members occupy different areas of memory, but in a union, the
members occupy the same area of memory. Thus, in the following type, for example:

union {
2 char c ;
3.3. DATA STRUCTURES 423

int d ;
4 } u;
✆✌
The programmer can access either ‘u.c’ or ‘u.d’, but not both at the same time. In the
following example, we modify only value of member ‘c’ and access it, we get the correct
result.

# include < stdio .h >
2 # include < string .h >

4 union Data {
char c ;
6 int d ;
};
8

int main () {
10 union Data data ;

12 data . c = 10;

14 printf ( " data . c : % d \ n " , data . c ) ;

16 return 0;
}
✆✌

data . c : 10
✆✌

0000 1010

data.c

In the following example, we modify values of members ‘c’ and ‘d’ and access it, we get the
incorrect result as ‘data.c’ and ‘data.d’ uses same memory space and ‘data.d’ overwrite
and modified the value of ‘data.c’ as well. Thus we get undesirable value of ‘data.c’ but
correct value of ‘data.d’.

1 # include < stdio .h >
# include < string .h >
3

union Data {
5 char c ;
int d ;
7 };

9 int main () {
union Data data ;
11
424 File & Data Structure

data . c = ’C ’;
13

data . d = 201170739;
15 /* | < - - - - - - - - - - - - - - data .d - - - - - - - - - - - - - - - >|*
* 00001011 11111101 10011111 00110011 *
17 * | < - data .c - >| */

19 printf ( " data . c : % c \ n " , data . c ) ;


printf ( " data . d : % d \ n " , data . d ) ;
21

return 0;
23 }
✆✌

data . c : 3
data . d : 201170739
✆✌

data.d

0000 1011 1111 1101 1001 1111 0011 0011

data.c

Since ‘data.c’ and ‘data.d’ occupy the same area of memory, so, modifying the value of one
member of union modifies the values of the other members, sometimes in unpredictable
ways. The size of a union is the size of its largest member. Another simple example is
given again.

# include < stdio .h >
2 # include < string .h >

4 union Data {
char c ;
6 int d ;
char str [15];
8 };

10 int main () {
union Data data ;
12 /* update shared memory as char */
data . c = ’C ’;
14 /* update shared memory as integer */
data . d = 201170739;
16 /* update shared memory as string */
strcpy ( data . str , " C Programming " ) ;
18

/* Read last updates as character */


3.3. DATA STRUCTURES 425

20 printf ( " data . c : % c \ n " , data . c ) ;


/* Read last updates as integer */
22 printf ( " data . d : % d \ n " , data . d ) ;
/* Read last updates as string */
24 printf ( " data . str : % s \ n " , data . str ) ;

26 return 0;
}
✆✌

data . c : C
data . d : 1917853763
data . str : C Programming
✆✌
union is used as shared structure in which shared memory is updated or accessed for
last value of any data type. Each element of the union structure reads/updates shared
memory bytes in same data type as it is declared in the union.

3.3.4 Stack
A stack is a particular kind of abstract data type or collection in which the principal (or
only) operations on the collection are the addition of an entity to the collection, known
as “push” and removal of an entity, known as “pop”. The relation between the push and
pop operations is such that the stack is a Last-In-First-Out (LIFO) data structure. In
most high level languages, a stack can be easily implemented either through an array or a
linked list. A stack needs to elements, one stack counter and second stack memory. Stack
memory either holds memory address of data located at the address (i.e. string stack) or
holds actual numeric values (integer stack). Stack pointer/counter controls to how many
elements may be pushed into a stack. It prevents pushing of an element in the memory
location that is not part of the stack. For example see following code which has declared
an array of 4 integers (i.e. stack size is four) and memory is allocated to store these 4
integer values.

1 int * myA ;
myA = malloc (4*4) ;
✆✌
Here, 16 bytes are reserved to hold 4 integer values. If we try to add 5th element into
this array, the array parameter reached beyond the allocated memory. It is violation of
shared memory. Stack will graphically represent as given below:

myA

Stack (0 to 3)
Low count High count

Here, pointer ‘myA’ should never be pushed beyond the range of 16 bytes. Initially,
‘myA’ is at the root of the stack, i.e. at the index 0. Now, push an integer into the stack.
426 File & Data Structure


* myA =10;
✆✌
Integer 10 is stored in the current memory location of ‘myA’. It is caller’s responsibility
to increase the pointer otherwise the next push shall put the new value in same location
and old value shall be overwritten by new value. The pointer location is incremented one
by

1 myA ++;
✆✌
Now, stack shall be looked like

myA

10

Stack (0 to 3)
Low count High count

By incrementing/decrementing the pointer within the memory allocated range, we


can either push a value into the stack or may popped a value from the stack. A sudden
jump of pointer within memory location is also permitted.

1 myA +3;
* myA =50;
✆✌
Now, stack shall be looked like

myA

10 50

Stack (0 to 3)
Low count High count

Note that, one integer is four bytes long, therefore, ‘myA+3’ shall make a jump of 12
bytes to the pointer ‘myA’. Stack may be declared as pointer or as an array.

int myA [4]; /* Declaration & memory allocation */
2 /* Other method */
int * myA ; /* Declaration */
4 myA = malloc (4*4) ; /* Memory allocation */
✆✌
Location of stack elements may be accessed by indexing or by dereferencing the array. If
stack is considered as a pointer then it is accessed as explained above. If it is considered
as an array then stack shall be looked like as given below and its elements can be accessed
by indexing them.
3.3. DATA STRUCTURES 427

myA[0] myA[1] myA[2] myA[3]

Stack (0 to 3)
Low count High count

In computer, index counting starts from 0 to infinity.

Push A Value
Pushing a value to a stack means adding an element into the stack. A value is pushed
at the current location of the pointer of stack counter (in case of array). Counter, some
time is used as index value. For example, in array type stack, 2nd element is pushed at
index 1 of ‘myA’.

myA [1] = 20;
✆✌

myA[1]

20

Stack (0 to 3)
Low count High count

If counter or index of array is incremented by more than one, then it is also called pushing
of element as the location of stack pointer is changed and new element shall be pushed
here.
myA[3]

20

Stack (0 to 3)
Low count High count

Pop A Value
Normally, system retrieves value from the current location of pointer or index counter.
Therefore, popping does not mean that value at particular location is chagned to null
before the changing the location of pointer or counter. If counter/index/pointer is decre-
mented by two without retrieving the values, then it is also said popping of elements even
though the values are intact at their memory locations.

myA[3]

10 20 30 40

Stack (0 to 3)
Low count High count
428 File & Data Structure

Assume that, initially pointer is at location ‘myA[3]’ and it is decremented by two


locations, then we say that 3rd and 4th elements are popped.

myA[1]

10 20 30 40

Stack (0 to 3)
Low count High count

Now, the pointer/counter is pointing to 2nd element of the stack. Adding of new
element will change the value at this memory location and retrieval may allow utilization
of the value stored at this location. Actually, it is user’s responsibility to control the
position of pointer or index within the stack.

Array in Stack
The array implementation aims to create an array where the first element (usually at the
zero-offset) is at the bottom. I.e., array[0] is the first element pushed onto the stack and
the last element popped off. The program must keep track of the size or the length of
the stack.

1 data type struct {
size_t size ; // element counter
3 int items [ STACKSIZE ]; // stack memory
} STACK ;
✆✌
The push() operation is used both to initialize the stack, and to store values into it. It
is responsible for inserting (copying) the value in array and for incremental the element
counter. Note that, when an element is pushed into the stack, counter should be increased
by one and when one element is removed from the stack, counter should be decreased by
one. It is also need to check that the array is not completely full or completely empty.

void push ( STACK * ps , int x ) {
2 if ( ps - > size == STACKSIZE ) {
fputs ( " Error : stack overflow \ n " , stderr ) ;
4 abort () ;
} else
6 ps - > items [ ps - > size ++] = x ;
}
✆✌
The pop() operation is responsible for removing a value from the stack, and decremented
the value of array. It is also need to check that the array is not already empty. Popping
of an element from the stack, decreases the counter by one.

1 int pop ( STACK * ps ) {
if ( ps - > size == 0) {
3 fputs ( " Error : stack underflow \ n " , stderr ) ;
abort () ;
5 } else
3.3. DATA STRUCTURES 429

return ps - > items [ - - ps - > size ];


7 }
✆✌
Following is the simple example that explains the stack in array by using struct structure
method.

1 # include < stdio .h >

3 # define MAXSIZE 5

5 struct stack /* Structure definition for stack */ {


int stk [ MAXSIZE ];
7 int top ;
};
9

struct stack s ;
11

/* Function declaration / Prototype */


13

void push ( void ) ;


15 int pop ( void ) ;
void display ( void ) ;
17

void main () {
19 int choice ;
int option = 1;
21

s . top = -1;
23

printf ( " STACK OPERATION \ n " ) ;


25 while ( option ) {
printf ( " - - - - - - - - - - - - - - - - - - - -\ n " ) ;
27 printf ( " 1 --> PUSH \ n " ) ;
printf ( " 2 --> POP \ n " ) ;
29 printf ( " 3 --> DISPLAY \ n " ) ;
printf ( " 4 --> EXIT \ n " ) ;
31 printf ( " - - - - - - - - - - - - - - - - - - - -\ n " ) ;

33 printf ( " Enter your choice : \ n " ) ;


scanf ( " % d " , & choice ) ;
35

switch ( choice ) {
37 case 1:
push () ;
39 break ;
case 2:
41 pop () ;
break ;
43 case 3:
display () ;
45 break ;
430 File & Data Structure

case 4:
47 return ;
}
49

fflush ( stdin ) ;
51 printf ( " Do you want to continue ( Type 0 or 1) ?\ n " ) ;
scanf ( " % d " , & option ) ;
53 }
}
55

/* Function to add an element to the stack */


57 void push () {
int num ;
59 if ( s . top == ( MAXSIZE - 1) ) {
printf ( " Stack is Full \ n " ) ;
61 return ;
} else {
63 printf ( " Enter a value \ n " ) ;
scanf ( " % d " , & num ) ;
65 s . top = s . top + 1;
s . stk [ s . top ] = num ;
67 }
return ;
69 }

71 /* Function to delete an element from the stack */


int pop () {
73 int num ;
if ( s . top == -1) {
75 printf ( " Stack is Empty \ n " ) ;
return ( s . top ) ;
77 } else {
num = s . stk [ s . top ];
79 printf ( " poped element is = % d \ n " , s . stk [ s . top ]) ;
s . top = s . top - 1;
81 }
return ( num ) ;
83 }

85 /* Function to display the status of the stack */


void display () {
87 int i ;
if ( s . top == -1) {
89 printf ( " Stack is empty \ n " ) ;
return ;
91 } else {
printf ( " \ nThe status of the stack is \ n " ) ;
93 for ( i = s . top ; i >= 0; i - -) {
printf ( " % d \ n " , s . stk [ i ]) ;
95 }
}
3.3. DATA STRUCTURES 431

97 printf ( " \ n " ) ;


}
✆✌
First screen of the program output is

--------------------
1 --> PUSH
2 --> POP
3 --> DISPLAY
4 --> EXIT
--------------------
Enter your choice :
✆✌

String in Stack
String can be stored as stack. To store string in stack, a stack variable of character type
is initialized. Generally, this stack variable is a two dimensional array, in which first
dimension represents the row number and second dimension represents to string size. For
example, a string stack of size 10, having largest string size of 20 characters is declared
as

1 char myStack [10][20];
✆✌
Here, stack size is 10 and we can put the string of length upto 20 characters.

3.3.5 Classes
In C, we can not declared function element inside the structure. This is why, it is hard
to call a function as object. Object oriented programming in C is restricted within scope
of the structure. There are four steps to be followed to create a function as object. The
steps involved, (i) create a class, (ii) deleted a class, (iii) update the class and (iv) access
the class.

Create Class
Here, using struct keyword, a class ‘myClass’ is declared. It has an element ‘variable’ of
int data type. The class is initialized to set the value of the class element ‘variable’ to 0.

1 typedef struct myClass {
int variable ;
3 } * MyClass ;

5 MyClass myNewClass () {
MyClass this = malloc ( sizeof * this ) ;
7 this - > variable = 0;
return this ;
9 }
✆✌
432 File & Data Structure

Delete Class
As each class when declared and called, a memory space is reserved to store data in
‘variable’. After execution of object function, the memory allocated, must be freed by
using free() function.

1 void myNewClass De l et e ( MyClass * this ) {
if ( this ) {
3 free (* this ) ;
* this = NULL ;
5 }
}
✆✌

Update Class
This function class updates the data of ‘variable’ according to the rules set by statements
and expressions inside this function.

void myNewClassSe t ( MyClass this ) {
2 this - > variable = 1;
}
✆✌

Access Class
It is main part of the program, from where we can access the object function. Result is
printed in output console by printf function.

1 int main () {
MyClass obj = myNewClass () ;
3 myNewClassSe t ( obj ) ;
printf ( " % d " , obj - > variable ) ;
5 myNewClassDe l et e (& obj ) ;
return 0;
7 }
✆✌
Complete example using above four steps is given below:

1 # include < stdlib .h >
# include < stdio .h >
3

typedef struct myClass {


5 int variable ;
} * MyClass ;
7

MyClass myNewClass () {
9 MyClass this = malloc ( sizeof * this ) ;
this - > variable = 0;
11 return this ;
}
13
3.3. DATA STRUCTURES 433

void myNewClass De l et e ( MyClass * this ) {


15 if ( this ) {
free (* this ) ;
17 * this = NULL ;
}
19 }

21 void myNewClassSe t ( MyClass this ) {


this - > variable = 1;
23 }

25 int main () {
MyClass obj = myNewClass () ;
27 myNewClassSe t ( obj ) ;
printf ( " % d " , obj - > variable ) ;
29 myNewClassDe l et e (& obj ) ;
return 0;
31 }
✆✌

3.3.6 Link List


Linked List (Array)
Arrays and linked list are linear data structure. In array, elements are stored in sequential
memory locations, while in linked list, elements are linked using pointers. Linked lists
are preferred over arrays as array has fixed size and insertion of element in between the
array elements is expensive.
myP

11 0×1225 34 0×a22c 56 0×a2cc NULL

0×042a 0×1225 0×a22c

Linked lists have some drawbacks too. (i) Random access is not allowed. and (ii)
extra memory space for a nextPtr is required with each element of the list. A linked list
node is created as given below:

1 struct list_Elem {
int data ;
3 struct list_Elem * nextElemPtr ;
};
✆✌
In this prototype, element of structure is structure itself. It is forbidden in the structure
definition. But in fact it only contains a nextPtr to itself. It is allowed as by the time
the compiler reaches the nextPtr declaration it already knows that there is such a thing
as a ‘struct list Elem’ so the declaration is permitted. In fact, it is possible to make a
incomplete declaration of a structure by saying
434 File & Data Structure


struct list_Elem ;
✆✌
at some point before the full declaration. This will allow the declaration of pointers before
the full declaration is seen. It is also important in the case of cross-referencing structures
where each must contain a nextPtr to the other, as shown in the following example.

1 struct s_1 ; /* Incomplete type */

3 struct s_2 {
int something ;
5 struct s_1 * sp ;
};
7

struct s_1 { /* Full declaration */


9 float something ;
struct s_2 * sp ;
11 };
✆✌
This illustrates the need for incomplete types. It also illustrates an important thing about
the names of structure members: they inhabit a name-space per structure, so element
names can be the same in different structures without causing any problems. Incomplete
types may only be used where the size of the structure isn’t needed yet. A full declaration
must have been given by the time that the size is used. The later full declaration mustn’t
be in an inner block because then it becomes a new declaration of a different structure.

1 struct x ; /* Incomplete type */

3 /* valid uses of the tag */


struct x * p , func ( void ) ;
5

void f1 ( void ) {
7 struct x {
int i ;
9 }; /* redeclaration ! */
}
11

/* full declaration now */


13 struct x {
float f ;
15 } s_x ;

17 void f2 ( void ) {
/* valid statements */
19 p = & s_x ;
* p = func () ;
21 s_x = func () ;
}
23

struct x func ( void ) {


25 struct x tmp ;
3.3. DATA STRUCTURES 435

tmp . f = 0;
27 return ( tmp ) ;
}
✆✌
The other principal way to get incomplete types is to declare arrays without specifying
their size, their type is incomplete until a later declaration provides the missing informa-
tion:

int ar [ ]; /* incomplete type */
2 int ar [5]; /* complete type */
✆✌
If you try that out, it will only work if the declarations are outside any blocks (external
declarations), but that’s for other reasons. There were three elements linked into the list,
which could have been built like this:

struct list_Elem {
2 int data ;
struct list_Elem * nextPtr ;
4 } ar [3];

6 main () {
ar [0]. data = 5; /* Add data to first element */
8 ar [0]. nextPtr = & ar [1]; /* Add address of second element */
ar [1]. data = 99; /* Add data to second element */
10 ar [1]. nextPtr = & ar [2]; /* Add address of third element */
ar [2]. data = -7; /* Add data to third element */
12 ar [2]. nextPtr = 0; /* mark end of list */
return (0) ;
14 }
✆✌
and the contents of the list can be printed in two ways. The array can be traversed in
order of index, or the pointers can be used as shown in the following example.

# include < stdio .h >
2 # include < stdlib .h >

4 struct list_Elem {
int data ;
6 struct list_Elem * nextPtr ;
} ar [3];
8

main () {
10

struct list_Elem * lp ;
12

ar [0]. data = 5; /* Add data to first element */


14 ar [0]. nextPtr = & ar [1]; /* Add address of second element */
ar [1]. data = 99; /* Add data to second element */
16 ar [1]. nextPtr = & ar [2]; /* Add address of third element */
ar [2]. data = -7; /* Add data to third element */
18 ar [2]. nextPtr = 0; /* mark end of list */
436 File & Data Structure

20 /* follow pointers */
lp = ar ;
22 while ( lp ) {
printf ( " contents % d \ n " , lp - > data ) ;
24 lp = lp - > nextPtr ;
}
26 exit ( EXIT_SUCCESS ) ;
}
✆✌

contents 5
contents 99
contents -7
✆✌

Linked List (Pointer)


A node in a list is memory location from where new data is stored. In C, a node is created
like

1 struct myNode {
int data ;
3 struct myNode * nextPtr ;
};
✆✌
Above structure has two elements, one for storing data and other for storing the address
of next element. Hence, each structure of a linked list is group of two contents, ‘data’
and ‘address of next data location’.

# include < stdio .h >
2 # include < stdlib .h >

4 struct myNode {
int data ;
6 struct myNode * nextPtr ;
};
8

void Push ( struct myNode ** myP , int value ) {


10 struct myNode * cNode = \
( struct myNode *) \
12 malloc ( sizeof ( struct myNode ) ) ;
cNode - > data = value ;
14 cNode - > nextPtr = (* myP ) ;
(* myP ) = cNode ;
16 printf ( " Value is % d at address % x \ n " , cNode - > data , & cNode - > data ) ;
printf ( " Address of next value % d is : % x \ n " ,( cNode - > data +1) ,
cNode - > nextPtr ) ;
18 }

20 int main () {
3.3. DATA STRUCTURES 437

struct myNode * head = NULL ;


22 int i =5;
while (i >0) {
24 Push (& head , i ) ;
i - -;
26 }
return 0;
28 }
✆✌

urrent value is 5 at address of 215 b 010 - - < - -+
Address of next value 6 is : 0 ( end of list ) |
Current value is 4 at address of 215 c 040 < -+ |
Address of next value 5 is : 215 b 010 - > - - > -| -+
Current value is 3 at address of 215 c 060 |
Address of next value 4 is : 215 c 040 - > - - > -+
Current value is 2 at address of 215 c 080
Address of next value 3 is : 215 c 060
Current value is 1 at address of 215 c 0 a 0
Address of next value 2 is : 215 c 080
✆✌
Above output is analyse in pair of output line. First line givens the stored value and
memory address where it is stored. Second line gives the address of previous linked
element. We can add a node by pushing a value at the beginning of the linked list. For
example, here we take a linked list like

myP

4 0×1225 7 0×a22c 9 0×a2cc NULL

0×042a 0×1225 0×a22c

and we want to add data 6 at the beginning of the linked list. Initially the memory
address of ‘myP’ pointer is ‘0×042a’. A new linked block (‘myNode’) is created as shown
below. Data (value 6) is pushed (at ‘0×d425’ say). The initial pointer address of ‘myP’ is
linked to the ‘nextPtr’ of newly created block and ‘myP’ is assigned the address of this
created block. I.e. now ‘myP’ is pointing to ‘0×042a’.

myP 6 0×042a

0×d425

4 0×1225 7 0×a22c 9 0×a2cc NULL

0×042a 0×1225 0×a22c


438 File & Data Structure

The C code for pushing data at the beginning of the linked list are given below:

# include < stdio .h >
2 # include < stdlib .h >

4 struct myNode {
int data ;
6 struct myNode * nextPtr ;
};
8

void Push ( struct myNode ** myP , int value ) {


10 struct myNode * childNode = \
( struct myNode *) \
12 malloc ( sizeof ( struct myNode ) ) ;
childNode - > data = value ;
14 childNode - > nextPtr = (* myP ) ;
(* myP ) = childNode ;
16 }

18 void printList ( struct myNode * currentNodeP t r ) {


while ( currentNodeP tr != NULL ) {
20 printf ( " % d " , currentNodePtr - > data ) ;
currentNode Pt r = currentNodePtr - > nextPtr ;
22 }
}
24

int main () {
26 struct myNode * head = NULL ;
Push (& head , 9) ;
28 Push (& head , 7) ;
Push (& head , 4) ;
30 Push (& head , 6) ;
printf ( " Linked list is : " ) ;
32 printList ( head ) ;
return 0;
34 }
✆✌

Linked list is : 6 4 7 9
✆✌
We can insert a node by adding a value inbetween of the linked list. For example, here
we take a linked list like

myP

4 0×1225 7 0×a22c 9 0×a2cc NULL

0×042a 0×1225 0×a22c


3.3. DATA STRUCTURES 439

and we want to add data 6 inbetween of the linked list. A new linked block (‘myNode’)
is created after the second list element as shown below. Data (value 6) is inserted (at
‘0×d425’ say). The ‘nextPtr’ of newly created block is assigned the address of data of 3rd
element. Address of inserted data of the newly inserted block is assigned to the ‘nextPtr’
of 2nd element of the linked list.

6 0×a22c
myP 0×d425

4 0×1225 7 0×d425 9 0×a2cc NULL

0×042a 0×1225 0×a22c

The C code for pushing data at the beginning of the linked list are given below:

1 # include < stdio .h >
# include < stdlib .h >
3

struct myNode {
5 int data ;
struct myNode * nextPtr ;
7 };

9 void Push ( struct myNode ** myP , int value ) {


struct myNode * childNode = \
11 ( struct myNode *) \
malloc ( sizeof ( struct myNode ) ) ;
13 childNode - > data = value ;
childNode - > nextPtr = (* myP ) ;
15 (* myP ) = childNode ;
}
17

void Insert ( struct myNode * NodeIndex , int value ) {


19 if ( NodeIndex == NULL ) {
printf ( " Node index cannot be NULL " ) ;
21 return ;
}
23 struct myNode * childNode = \
( struct myNode *) \
25 malloc ( sizeof ( struct myNode ) ) ;
childNode - > data = value ;
27 childNode - > nextPtr = NodeIndex - > nextPtr ;
NodeIndex - > nextPtr = childNode ;
29 }

31 void printList ( struct myNode * currentNodeP t r ) {


while ( currentNodeP tr != NULL ) {
440 File & Data Structure

33 printf ( " % d " , currentNodePtr - > data ) ;


currentNode Pt r = currentNodePtr - > nextPtr ;
35 }
}
37

int main () {
39 struct myNode * head = NULL ;
Push (& head , 9) ;
41 Push (& head , 7) ;
Insert ( head - > nextPtr , 6) ;
43 Push (& head , 4) ;
printf ( " Linked list is : " ) ;
45 printList ( head ) ;
return 0;
47 }
✆✌

Linked list is : 4 6 7 9
✆✌
Similarly, we can append elements in a linked list. The C code for appending elements in
linked list are given below:

1 # include < stdio .h >
# include < stdlib .h >
3

struct myNode {
5 int data ;
struct myNode * nextPtr ;
7 };

9 void Push ( struct myNode ** myP , int value ) {


struct myNode * childNode = \
11 ( struct myNode *) \
malloc ( sizeof ( struct myNode ) ) ;
13 childNode - > data = value ;
childNode - > nextPtr = (* myP ) ;
15 (* myP ) = childNode ;
}
17

void Append ( struct myNode ** myP , int value ) {


19 struct myNode * childNode = \
( struct myNode *) \
21 malloc ( sizeof ( struct myNode ) ) ;
struct myNode * last = * myP ;
23 childNode - > data = value ;
childNode - > nextPtr = NULL ;
25 if (* myP == NULL ) {
* myP = childNode ;
27 return ;
}
29 while ( last - > nextPtr != NULL )
last = last - > nextPtr ;
3.3. DATA STRUCTURES 441

31 last - > nextPtr = childNode ;


return ;
33 }

35 void printList ( struct myNode * currentNodeP t r ) {


while ( currentNodeP tr != NULL ) {
37 printf ( " % d " , currentNodePtr - > data ) ;
currentNode Pt r = currentNodePtr - > nextPtr ;
39 }
}
41

int main () {
43 struct myNode * head = NULL ;
Push (& head , 7) ;
45 Push (& head , 1) ;
Append (& head , -15) ;
47 Push (& head , 10) ;
Append (& head , -45) ;
49 Push (& head , 7) ;
Push (& head , -5) ;
51 printf ( " Linked list is : " ) ;
printList ( head ) ;
53 return 0;
}
✆✌

Linked list is : -5 7 10 1 7 -15 -45
✆✌
To delete an element from a linked list, we just bypass the elements being deleted as
shown in the following figures.

myP

4 0×1225 7 0×a22c 9 0×a2cc NULL

0×042a 0×1225 0×a22c

We have a link list as shown above and we want to delete element having value 7. To
do so, we just skip this element and linked first element with third element. as shown
below:
myP

4 0×a22c 7 0×a22c 9 0×a2cc NULL

0×042a 0×1225 0×a22c

The C code for appending elements in linked list are given below:
442 File & Data Structure


1 # include < stdio .h >
# include < stdlib .h >
3

struct myNode {
5 int data ;
struct myNode * nextPtr ;
7 };

9 void Push ( struct myNode ** myP , int value ) {


struct myNode * childNode = \
11 ( struct myNode *) \
malloc ( sizeof ( struct myNode ) ) ;
13 childNode - > data = value ;
childNode - > nextPtr = (* myP ) ;
15 (* myP ) = childNode ;
}
17

void deleteNode ( struct myNode ** head_ref , int key ) {


19 struct myNode * temp = * head_ref , * prev ;
if ( temp != NULL && temp - > data == key ) {
21 * head_ref = temp - > nextPtr ;
free ( temp ) ;
23 return ;
}
25 while ( temp != NULL && temp - > data != key ) {
prev = temp ;
27 temp = temp - > nextPtr ;
}
29 if ( temp == NULL ) return ;
prev - > nextPtr = temp - > nextPtr ;
31 free ( temp ) ;
}
33

void printList ( struct myNode * currentNodeP t r ) {


35 while ( currentNodeP tr != NULL ) {
printf ( " % d " , currentNodePtr - > data ) ;
37 currentNodePt r = currentNodePtr - > nextPtr ;
}
39 }

41 int main () {
struct myNode * head = NULL ;
43 Push (& head , 9) ;
Push (& head , 7) ;
45 Push (& head , 4) ;
printf ( " Created Linked list is : " ) ;
47 printList ( head ) ;
deleteNode (& head , 4) ;
49 printf ( " \ nCreated Linked list is : " ) ;
printList ( head ) ;
3.3. DATA STRUCTURES 443

51 return 0;
}
✆✌

Created Linked list is : 4 7 9
Created Linked list is : 7 9
✆✌

3.3.7 Heap
A heap is a specialized tree-based data structure that satisfies the heap property that if P
is a parent node of C, then the key (the value) of P is either greater than or equal to (in
a max heap) or less than or equal to (in a min heap) the key of C. The node at the “top”
of the heap (with no parents) is called the root node. The heap is one maximally efficient
implementation of an abstract data type called a priority queue, and in fact priority
queues are often referred to as “heaps”, regardless of how they may be implemented.

100

193 36

17 2 25 1

2 7

Heaps are implemented in an array of either fixed size or of dynamic size. Each heap
is required to perform internal operation during the insertion, deletion or appending of an
element. The most common form of heap is binary heap. Binary heaps are represented
by using an array only.

1 2

3 4 5 6

7 8 9 10

0 1 2 3 4 5 6 7 8 9 10
Figure 3.4: Zero-based Array.

The first or last element of the array is root. The next two elements of the array
contain its children. The next four contain the four children of the two child nodes, etc.
Thus the children of the node at position n would be at positions 2n and 2n + 1 if index
444 File & Data Structure

of the first element of an array is started with one, or 2n + 1 and 2n + 2 if index of the
first element of an array is started with zero.

2 3

4 5 6 7

8 9 10 11

1 2 3 4 5 6 7 8 9 10 11
Figure 3.5: One-based Array.

Construction
One dimensional array based heap is constructed by creating an array of requisite size as
shown below:

int myHeap [20]; // heap of size of 20 elements
✆✌

index 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

Each heap cell is of four bytes size and one-based indexed. We can add twenty elements
in these cells.

Add/Insert an Element
Let an element is being added in the one-base array at the index of 2n. This element is
compared with all previous corresponding child nodes at index locations given by n = n/2.
If value at a child node is greater than the element being added/inserted, it is swapped
mutually. This process undergo until the element is not become greater than the value
at previous child node. Consider an one-based one dimensional array as shown below:
3
2 4 6 9
index 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

Let current element 3 is being added at the index location 16. Now, 3 is compared
with value at index location 16/2 = 8, i.e. with value 9. Here, 3 < 9, hence 9 is placed in
the index location 16 and 3 is being try to put at index location 8 as shown below:
3
2 4 6 9
index 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
3.3. DATA STRUCTURES 445

Now, 3 is being put at the index location 16/2 = 8, but before inserting it at this
location, we again compare it with the value stored at index location 8/2 = 4. So, again
3 < 6, hence 6 is placed at the index location 8 as shown below:
3
2 4 6 9
index 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

This process is iterated until 3 became larger than value at previous child node. Now,
3 is being put at the index location 8/2 = 4, but before inserting it at this location, we
again compare it with the value stored at index location 4/2 = 2. So, again 3 < 4, hence
4 is placed at the index location 4 as shown below:
3
2 4 6 9
index 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

Finally, 3 became larger than its previous corresponding child node where value 2 is
stored. So, 3 is placed at index location 2 as shown below:

2 3 4 6 9
index 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

The equivalent code example is given below:



1 void Insert ( int v ) {
heapSize ++;
3 heap [ heapSize ] = v ;
int current_node = heapSize ;
5 while ( heap [ current_node / 2] > v ) {
heap [ current_node ] = heap [ current_node / 2];
7 current_node /= 2;
}
9 heap [ current_node ] = v ;
}
✆✌

Remove an Element
In heap an element can be deleted, but after each removal of an element, the heap is
reorganized. Consider a one-based one-dimensional heap array as shown below:

2 3 4 6 9
index 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

Suppose we want to remove the element 4 at index location 4. To do this, we first


remove it from the list as shown below:
446 File & Data Structure

2 3 6 9
index 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

Now, we should have rearrange all the elements right side to the element being re-
moved, i.e. element at index location 8 shall be shifted to index location 4 and element
at index location 16 shall be shifted to index location 8 and so on.

2 3 6 9
index 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

Finally, the new heap list shall be looked like as given below:

2 3 6 9
index 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

3.3.8 Tree
Binary tree is the data structure to maintain data into memory of program. There exists
many data structures but they are used as per their performance. In binary tree, each
node can have two child nodes and each child node can itself be a small binary tree.

3 4

7 6 9 8

In this binary tree, we add a child node to a parent node. Child nodes have the
reference to their parent node. By this way each child node is linked with its parent node
& parent node is linked with its parent node and so on.

Create Tree Structure


Here, we have create a coordinate based tree nodes. A node contains the parent’s coor-
dinate, current node coordinate and node value. The node structure is like (xold, yold,
xnew, ynew, value). For it, a structure is created as shown below:

struct TreeData {
2 int x_node ;
int y_node ;
4 int x_child_node ;
int y_child_node ;
3.3. DATA STRUCTURES 447

6 int val ;
};
8

/* Current node coordinates . */


10 struct NewCoord {
int x ;
12 int y ;
} nc ;
✆✌

Insert Tree Data


First we get the new coordinate of current node, i.e. child node. The value is linked with
parent node and saved in a data file. A node is in a sequential structure of xold, yold,
xnew, ynew, value.

1 int insert ( struct TreeData * td , FILE * fp , int x_node , int y_node ,
int val ) {
int xnew ;
3 int ynew ;
xnew = nc . x + 1;
5 ynew = nc . y + 1;
if ( xnew < x_node || ynew < y_node ) {
7 return 1;
}
9 td - > x_node = x_node ;
td - > y_node = y_node ;
11 td - > x_child_node = xnew ;
td - > y_child_node = ynew ;
13 td - > val = val ;
fwrite ( td , sizeof ( struct TreeData ) , 1 , fp ) ;
15 nc . x = xnew ;
nc . y = ynew ;
17 return 0;
}
✆✌

Display Tree Data


Here we search all the child nodes and values of the parent node (xold, yold). Scann the
file and put the output in console when parent node is equal to the supplied parent node.

int view ( struct TreeData * td , FILE * fp , int x_node , int y_node ) {
2 printf ( " %10 s %10 s %10 s %10 s %10 s \ n " ,
" parent x " ,
4 " parent y " ,
" child x " ,
6 " child y " ,
" Value " ) ;
8 printf ( " %50 s \ n " ," - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - " ) ;
int s ;
448 File & Data Structure

10 s = fread ( td , sizeof ( struct TreeData ) , 1 , fp ) ;


while ( s > 0) {
12 if ( td - > x_node == x_node && td - > y_node == y_node ) {
printf ( " %10 d %10 d %10 d %10 d %10 d \ n " ,
14 td - > x_node ,
td - > y_node ,
16 td - > x_child_node ,
td - > y_child_node ,
18 td - > val ) ;
}
20 s = fread ( td , sizeof ( struct TreeData ) , 1 , fp ) ;
}
22 return 0;
}
✆✌

Delete Tree Data


In this step, we search the required parent node whose child node values are to be emptied.
First the data from data file is saved into temporary file with deleted values of all child
nodes. Original file is deleted and temporary file is renamed to the data file.

1 int delete ( struct TreeData * td , FILE * fp , int x_node , int y_node ) {
int s ;
3 FILE * tmp ;
tmp = fopen ( " Tmp . txt " , " wb " ) ;
5 s = fread ( td , sizeof ( struct TreeData ) , 1 , fp ) ;
while ( s > 0) {
7 if ( td - > x_node == x_node && td - > y_node == y_node ) {
td - > val = 0;
9 fwrite ( td , sizeof ( struct TreeData ) , 1 , tmp ) ;
} else {
11 fwrite ( td , sizeof ( struct TreeData ) , 1 , tmp ) ;
}
13 s = fread ( td , sizeof ( struct TreeData ) , 1 , fp ) ;
}
15 fclose ( tmp ) ;
remove ( fp ) ;
17 rename ( " Tmp . txt " , " TreeNode . txt " ) ;
return 0;
19 }
✆✌
Here is complete code for data tree.

1 # include < stdio .h >

3 /* Three data structure . x_node & y_node *


* represents to the parent node . While *
5 * x_child_node & y_child_node represents *
* to the child node . val is data value at *
7 * child node . Parent node is link of the *
3.3. DATA STRUCTURES 449

* child node . */
9 struct TreeData {
int x_node ;
11 int y_node ;
int x_child_node ;
13 int y_child_node ;
int val ;
15 };

17 /* Current node coordinates . */


struct NewCoord {
19 int x ;
int y ;
21 } nc ;

23 /* Insert data at current child node ,*


* linked with its parent node . */
25 int insert ( struct TreeData * td , FILE * fp ,
int x_node , int y_node , int val ) {
27 int xnew ;
int ynew ;
29 xnew = nc . x + 1;
ynew = nc . y + 1;
31 if ( xnew < x_node || ynew < y_node ) {
return 1;
33 }
td - > x_node = x_node ;
35 td - > y_node = y_node ;
td - > x_child_node = xnew ;
37 td - > y_child_node = ynew ;
td - > val = val ;
39 fwrite ( td , sizeof ( struct TreeData ) , 1 , fp ) ;
nc . x = xnew ;
41 nc . y = ynew ;
return 0;
43 }

45 /* View all the child nodes of the parent node . */


int view ( struct TreeData * td , FILE * fp , int x_node , int y_node ) {
47 printf ( " %10 s %10 s %10 s %10 s %10 s \ n " ,
" parent x " ,
49 " parent y " ,
" child x " ,
51 " child y " ,
" Value " ) ;
53 printf ( " %50 s \ n " ," - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - " ) ;
int s ;
55 s = fread ( td , sizeof ( struct TreeData ) , 1 , fp ) ;
while ( s > 0) {
57 if ( td - > x_node == x_node && td - > y_node == y_node ) {
printf ( " %10 d %10 d %10 d %10 d %10 d \ n " ,
450 File & Data Structure

59 td - > x_node ,
td - > y_node ,
61 td - > x_child_node ,
td - > y_child_node ,
63 td - > val ) ;
}
65 s = fread ( td , sizeof ( struct TreeData ) , 1 , fp ) ;
}
67 return 0;
}
69

/* Delete all values at parent node . */


71 int delete ( struct TreeData * td , FILE * fp ,
int x_node , int y_node ) {
73 int s ;
FILE * tmp ;
75 tmp = fopen ( " Tmp . txt " , " wb " ) ;
s = fread ( td , sizeof ( struct TreeData ) , 1 , fp ) ;
77 while ( s > 0) {
if ( td - > x_node == x_node && td - > y_node == y_node ) {
79 td - > val = 0;
fwrite ( td , sizeof ( struct TreeData ) , 1 , tmp ) ;
81 } else {
fwrite ( td , sizeof ( struct TreeData ) , 1 , tmp ) ;
83 }
s = fread ( td , sizeof ( struct TreeData ) , 1 , fp ) ;
85 }
fclose ( tmp ) ;
87 remove ( fp ) ;
rename ( " Tmp . txt " , " TreeNode . txt " ) ;
89 return 0;
}
91

/* Main function part . */


93 int main () {
FILE * fp ;
95 struct TreeData td ;
/* Open file and write tree data . */
97 fp = fopen ( " TreeNode . txt " , " wb + " ) ;
int i = 0;
99 while ( i < 100) {
insert (& td , fp , i % 5 , i % 6 , i ) ;
101 i ++;
}
103 fclose ( fp ) ;
/* Open file and Delete specific tree node data . */
105 fp = fopen ( " TreeNode . txt " , " rb " ) ;
delete (& td , fp , 1 , 1) ;
107 fclose ( fp ) ;
/* Open file and view tree node data . */
109 fp = fopen ( " TreeNode . txt " , " rb " ) ;
3.3. DATA STRUCTURES 451

view (& td , fp , 1 , 1) ;
111 fclose ( fp ) ;
return 0;
113 }
✆✌

3.3.9 Binary Tree


452 Miscellaneous
4.1. ERROR HANDLING FUNCTIONS 453

4 Miscellaneous

4.1 Error Handling Functions


Following functions are used for handling of errors arises when a program is compiled or
executed. Some of the errors are thrown by compiler when a program is compiles. These
errors arise if we try to use undefined functions, misprints or using wrong procedures. Run
time errors arise when we try to access restricted or denied memory locations, try to create
a wrong file structure or wrote a program which is not compatible to hardware/software.

4.1.1 clearerr function


The synopsis of the function is

1 # include < stdio .h >
void clearerr ( FILE * stream ) ;
✆✌
The clearerr function clears the end-of-file and error indicators for the stream pointed-by
‘stream’. A simple example is

# include < stdio .h >
2

int main () {
4 FILE * fName ;
fName = fopen ( " F . txt " , " r " ) ;
6 if ( fName == NULL )
perror ( " Can not open the file " ) ;
8 else {
fputc ( ’x ’ , fName ) ;
10 if ( ferror ( fName ) ) {
printf ( " Can not write in file .\ n " ) ;
12 clearerr ( fName ) ;
}
14 fgetc ( fName ) ;
if (! ferror ( fName ) )
16 printf ( " Reading from file .\ n " ) ;
fclose ( fName ) ;
18 }
return 0;
20 }
✆✌

Can not write in file .
Reading from file .
✆✌
454 Miscellaneous

4.1.2 ferror function


The synopsis of the function is

# include < stdio .h >
2 int ferror ( FILE * stream ) ;
✆✌
The ferror function tests the error indicator for the stream pointed-by ‘stream’ and returns
nonzero if and only if the error indicator is set for stream, otherwise it returns zero. A
simple example is

# include < stdio .h >
2

int main ( void ) {


4 int a ;
FILE * fp ;
6 /* file . txt must be in executable ’s dir */
fp = fopen ( " file . txt " , " rb " ) ;
8 /* Read single ints at a time , stopping on EOF or error : */
while ( fread (& a , sizeof ( int ) , 1 , fp ) , ! feof ( fp ) &&
! ferror ( fp ) ) {
10 printf ( " I read % d \ n " , a ) ;
}
12 if ( feof ( fp ) )
printf ( " End of file was reached .\ n " ) ;
14 if ( ferror ( fp ) )
printf ( " An error occurred .\ n " ) ;
16 fclose ( fp ) ;
return 0;
18 }
✆✌

I read 1735287116
I read 1701279073
End of file was reached .
✆✌

4.1.3 perror function


The synopsis of the function is

1 # include < stdio .h >
void perror ( const char * s ) ;
✆✌
The perror function maps the error number in the integer expression errno to an error
message. It writes a sequence of characters to the standard error stream thus: first,
if ‘s’ is not a null pointer and the character pointed-by ‘s’ is not the null character,
the string pointed-by ‘s’ followed by a colon (:) and a space; then an appropriate error
message string followed by a new-line character. The contents of the error message are
the same as those returned by the strerror function with the argument errno, which are
implementation-defined. A simple example is
4.1. ERROR HANDLING FUNCTIONS 455


# include < stdio .h >
2 /* Must include to see " errno " */
# include < errno .h >
4

int main ( void ) {


6 if ( fseek ( stdin , 10 L , SEEK_SET ) < 0)
perror ( " fseek " ) ;
8 /* Stop using this stream */
fclose ( stdin ) ;
10 if ( fseek ( stdin , 20 L , SEEK_CUR ) < 0) {
if ( errno == EBADF ) {
12 perror ( " fseek again , EBADF " ) ;
} else {
14 perror ( " fseek again " ) ;
}
16 }
return 0;
18 }
✆✌

fseek : Illegal seek
fseek again , EBADF : Bad file descriptor
✆✌

4.1.4 Segmentation Fault


Segmentation fault is shown by different hardware and operating system with different
ways. Some prominent reason of segmentation fault are
1. Dereferencing null pointers.
2. Accessing non existent pointer.
3. Attempting to access a nonexistent memory address.
4. Attempting to access memory the program does not have rights to.
5. Attempting to write read-only memory.
6. Dereferencing or assigning to an uninitialized pointer.
7. Dereferencing or assigning to a freed pointer.
8. A buffer overflow.
9. A stack overflow.
10. Attempting to execute a program that does not compile correctly.
456 Miscellaneous


# include < stdio .h >
2

int main () {
4 FILE * fl ; /* File pointer */
fclose ( fl ) ; /* Trying to close file pointer *
6 * that was never opened before . *
* Cause for segmentation fault . */
8 return 0; /* Return sucess . */
}
✆✌

4.2 Reserved Keyword


There are 32 keywords in C89 while 37 reserve keywords in C99 and 44 reserve keywords
in C11. These keywords are solely reserved for internal use by C compilers. They can not
be redefined by programmer or can not be used as literals. The list of reserved keywords
is given below.

auto double int static


break else long struct
case enum register switch
char extern restrict union
const float return unsigned
continue for short void
default goto signed volatile
do if sizeof while
Bool Complex Imaginary inline
restrict
Alignas Alignof Atomic Generic
Noreturn Static assert Thread local

4.3 Case Sensitivity


C identifiers are case sensitive i.e. myname, MYNAME, and MyName are the names
of three different objects. Some linker may map external identifiers to a single case,
although this is uncommon in most modern linker. See the following example, in which
two variables ‘y’ and ‘Y’ are declared and initialized. They are treated as two different
variables and can be accessed differently.

1 # include < stdio .h >

3 int main () {
// Declare a variable y
5 int y = 1;
// Declare a variable Y
7 int Y = 2;
printf ( " y is % d and Y is % d \ n " , y , Y ) ;
4.4. COMMENTING 457

9 return 0;
}
✆✌

y is 1 and Y is 2
✆✌

4.4 Commenting
Commenting inside the C code is a beautiful feature of C language. It provides the utility
for writing managed codes. Commenting occurs within the C codes. It may be of a single
line or can span in multiple lines. There are two way of commenting. First is single line
commenting which started with ‘//’. Anything written in the line started with ‘//’ are
skipped by the C compilers. Presence of another ‘//’ in the same line does not end the
single line comment. Second method is multi-line commenting. Text starting with the
token ‘/*’ are treated as a comments and ignored. The multi-line comments are ended at
next token ‘*/’.

1 # include < stdio .h >

3 int main () {
// Declare a variable // as y
5 int y ;
/* <-- given expression *
7 * y = (5 + 3 - 4) % 2 *
* is computed in steps *
9 * y = (8 - 4) % 2 *
* y = 4 % 2 = 0 --> */
11 y = (5 + 3 - 4) % 2;
printf ( " Result is : % d \ n " , y ) ;
13 return 0;
}
✆✌

Result is : 0
✆✌
458 Library
5.1. THROUGH NETBEAN 459

5 Library

In computer science, there are two types libraries. (i) A static library is a collection of
object files which contain library routines and data. It is built in such a way that the
link editor will incorporate a copy of only those object files that hold the functions and
data referenced in the program into the executable at link time. (ii) A shared library is a
shared object file that contains functions and data. It is built in such a way that the link
editor will only store in the executable the name of the shared library and information
about the symbols referenced by the executable. At run time the dynamic linker, a.k.a.
the program interpreter in ELF, will map the shared library into the virtual address space
of the process image of the executable and resolve by name the symbols in the shared
library used by the executable. That is process is also called dynamic linking. Here, we
will write example code for linking static libraries in C. There are three steps of static
library use. First is generation of library, second is linking of library and third is its
application.

5.1 Through NetBean


5.1.1 Create Library
To create a library first create a C static or dynamic library project “myLib” in Netbean
with cygwin gcc compiler. Create two files, myFunc.c and myFunc.h within the “myLib”
project. The codes of these two files are respectively

1 # include < stdio .h >

3 void myFunc ( void ) {


puts ( " Hello , I ’m a shared library " ) ;
5 }
✆✌

1 # ifndef MYFUNC_H
# define MYFUNC_H
3

# ifdef __cplusplus
5 extern " C " {
# endif
7

// static library function


9 extern void myFunc ( void ) ;

11 # ifdef __cplusplus
}
13 # endif
460 Library

15 # endif /* MYFUNC_H */
✆✌
Open project properties and click on C-Compiler or Linker option. Set tool to “gcc -
shared”. Here, keyword “-shared” makes a library shareble. Compile this library and you
will get a library for use with other program.

5.1.2 Link Library


Now create second project in Netbean with MinGW, say ‘myProg’. Copy your generated
library in this new project (say ‘myProg’) from where you can use it. Open the project
property and go to the linker and add following to linker:

1 gcc -L " < path to library > " -l < static / dynamic lib name >
✆✌
Here, ‘path to library’ is absolute path of your generated library that is put within your
‘myProg’ project or else where. Copy ‘myFunc.h’ into source directory of this new project
and create new “main.c” file. The code of main file are

1 # include < stdio .h >
# include " myFunc . h "
3

int main ( void ) {


5 puts ( " This is a shared library test ... " ) ;
myFunc () ;
7 return 0;
}
✆✌
Compile and build this program with MinGW gcc compiler and run this program. You
will get the desire output.

This is a shared library test ...
Hello , I ’ m a shared library
✆✌

5.2 From Command Line


5.2.1 Create Library
Create two files, myFunc.c and myFunc.h with following codes and put them under a
directory (say “C:
myLib”) that is accessible to you.

# include < stdio .h >
2

void myFunc ( void ) {


4 puts ( " Hello , I ’m a shared library " ) ;
}
✆✌
5.2. FROM COMMAND LINE 461


1 # ifndef MYFUNC_H
# define MYFUNC_H
3

# ifdef __cplusplus
5 extern " C " {
# endif
7

// static library function


9 extern void myFunc ( void ) ;

11

# ifdef __cplusplus
13 }
# endif
15

# endif /* MYFUNC_H */
✆✌
From the command prompt, we can create static and dynamic libraries by using following
commands with cygwin gcc.

gcc - fPIC -c -o myFunc . o myFunc . c -I " C :\ myLib "
2 gcc - shared -o libmyFunc . dll myFunc . o
✆✌
Here, ‘-fPIC’ tells GCC that to create Position Independent Code using relative addresses
rather than absolute addresses because these libraries can be loaded multiple times. Here,
this flag may be omitted. If environment for ‘gcc’ compiler is not registered then use
absolute path of the gcc executable like “C:
MinGW
bin
gcc.exe”. ‘-I’ flag is used to add the directory where relevant header files are placed. Here,
the prefix “lib” to ‘myFunc.dll’ required when we link this library to a program during
program’s compilation with ‘-l’ flag identifier. Now out library is ready to be used.

5.2.2 Link Library


Write a new program file “main.c”. The code of main file are

# include < stdio .h >
2 # include " myFunc . h "

4 int main ( void ) {


puts ( " This is a shared library test ... " ) ;
6 myFunc () ;
return 0;
8 }
✆✌
Copy ‘myFunc.h’ into the same directory (say “C:
myLib”) where this code file is placed. Now, compile this program file with MinGW gcc
compiler as command given below:
462 Library


gcc -c -o main . o main . c -I " C :\ myLib "
2 gcc -o main . exe main . o -L " C :\ myLib " - lmyFunc
✆✌
Here, “-L” flag represents to library path where user’s library is placed. “-l” represents
to linked library name with the user’s program. “-I” represents to include path of header
files. Name of static or dynamic library is supplied without prefix “lib” and extension
name “.dll”. The flag ‘-l’ searches for the named library by pre-pending ‘lib’ automatically.
If libraries are placed in the same directory (say “C:
myLib”) where program file is then use following modified command:

gcc -o main . exe main . o ./ - lmyFunc
✆✌
The output of above program is

This is a shared library test ...
Hello , I ’ m a shared library
✆✌
Here, both static and dynamic libraries can be used with C program. But dynamic
libraries are preferred over the static libraries as and when dynamic libraries are upgraded,
program does not need recompilation with upgraded dynamic libraries.

5.3 Load Library Dynamically


In C programming, with POSIX system, we can load a library dynamically by using
functions dlopen(), dlsym() and dlclose(). These functions are found in ‘dlfcn.h’. Note
that this library only loaded library function for its calling. It does not check input and
output parameters. Parameters are checked by function itself when it is called.
dlopen This function is used to open a static or dynamic library from user’s directory
and reading of its export table that contains the function names of the library. It accepts
two arguments. First is library name with absolute/relative path and second is mode
of opening of the library. It returns a ‘handle’ pointing to the library. If it is unable
to locate/open a file, it returns NULL or an error value. If NULL is used as file name
argument to this function, then it will export symbols in the executable for currently
loaded shared libraries via dlsym function.

void * myLib = dlopen ( < name > , < mode >)
✆✌
Here name of library is constant character type and mode of opening of library is either
of the ‘RTLD NOW’ (for immediate function binding), ‘RTLD LAZY’ (for lazy function
binding), ‘RTLD GLOBAL’ or ‘RTLD LOCAL’. See the example below:

1 # include < stdio .h >
# include < stdlib .h >
3 # include < dlfcn .h >

5 int main () {
void * myLib ;
5.3. LOAD LIBRARY DYNAMICALLY 463

7 myLib = dlopen ( " libcdy . dll " , RTLD_LAZY ) ;


if ( myLib == NULL ) {
9 printf ( " Can not locate library % s \ n " , " libcdy . dll " ) ;
}
11 return EXIT_SUCCESS ;
}
✆✌

dlsym After a shared library is loaded into the address space of the running process,
this function is used to obtain the address of an exported symbol in that shared library.
We can now access the function or data through the address returned from dlsym function.
This function searches for the function supplied it to as its second argument and returns
its address. If the function could not be found, it returns NULL. The return value must
be casted to a proper function pointer before it can be used. Its syntax is looked like as

void (* fptr ) () ;
2 fptr = dlsym ( < handle > , < function name >) ;
✆✌
See the example below:

# include < stdio .h >
2 # include < stdlib .h >
# include < dlfcn .h >
4

int main () {
6 void * myLib ;
void (* fptr ) () ;
8 myLib = dlopen ( " libcdy . dll " , RTLD_LAZY ) ;
if ( myLib != NULL ) {
10 fptr = dlsym ( myLib , " myFunc " ) ;
if (! fptr ) {
12 printf ( " Can not locate function % s \ n " , " myFunc " ) ;
}
14 /* Call the function through its pointer */
fptr () ;
16 } else {
printf ( " Error in opening % s library !! " , " libcdy . dll " ) ;
18 }
if ( myLib != NULL )
20 dlclose ( myLib ) ;
return EXIT_SUCCESS ;
22 }
✆✌

dlclose Each handle opened with dlopen() function must be closed by using dlclose()
function. This function returns ‘-1’ if it failed to close a handle refering to the opened
library.

int v = dlclose ( < handle >) ;
✆✌
464 Library

dlerror This function is used to retrieve a text message that is describing to the most
recent error occurred during the process of either of the functions dlopen(), dlsym() and
dlclose().

1 char * v = dlerror ( void ) ;
✆✌

You might also like