Professional Documents
Culture Documents
Notes For C Programming For BCA, MCA, BSc. MSC, BE & B.tech 1st Year
Notes For C Programming For BCA, MCA, BSc. MSC, BE & B.tech 1st Year
Notes For C Programming For BCA, MCA, BSc. MSC, BE & B.tech 1st Year
C P ROGRAMMING
A N I NTRODUCTION
Arun Umrao
www.sites.google.com/view/arunumrao
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
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
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 1 3 4 5
In above figure, dot (·) represents to decimal symbol separating whole part (213) from
fractional part (45) of the given number 213.45.
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 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
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
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.
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.
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
Now write the remainders in forward order by prefixing decimal sign ·. The binary
equivalent to the decimal fraction 0.25 is
D7 D6 D5 D4 D3 D2 D1 D0
MSB LSB
1 1 1 1 1 1 1 1
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
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
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.
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
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
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
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.
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.
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
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
Solution The variable of short type will read data in group of two bytes.
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.
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 . */
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
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
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
✞
1 # include < stdio .h >
# include < stdlib .h >
3
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 >
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
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 >
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 >
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 >
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 >
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
✞
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
✞
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
‘+’ 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 >
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 >
/* 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 >
The output of above program after computing the four bytes long binary sequence is
✞
Value of i is : 1633772130
✆✌
✞
1 # include < stdio .h >
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 !
✆✌
int main () {
4 int i = 5;
switch ( i ) {
6 case 1 ... 10:
36 Basic C
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.
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.
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.
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
B[2] B[3] B[4] B[5] B[6] B[7] B[8] B[9] B[10] B[11]
K L
c s
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
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 ) ;
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
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
✆✌
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]
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.
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
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
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
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
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
✞
# include < stdio .h >
2
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
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
✆✌
are five major datatypes which are given in the following table. C also allow suitable
combinations of numeric datatypes for long numerical values.
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.
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
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
✞
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 };
struct st {
5 int x ;
float y ;
7 char * z ;
};
9
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 };
✞
1 # include < stdio .h >
# include < stdlib .h >
3
struct st {
5 int x ;
float y ;
7 char * z ;
};
9
3 /* It is address of integer i *
* where value 10 is stored . */
5 int * j =& i ;
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
✆✌
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
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
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 >
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 () {
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
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
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
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
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 >
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;
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
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
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 >
4 int main () {
const volatile int i = 10;
1.3. VARIABLES 77
4 struct myS {
int i ;
6 int j ;
};
8
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 >
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
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 >
✞
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.
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 >
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
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.
3 int main () {
register int i ;
5
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
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.
3 void myFuncA () ;
void myFuncB () ;
5
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 " ) ;
}
✆✌
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 >
7 int main () {
int i = 2;
1.4. C OPERATORS 91
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.
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
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
✆✌
3 int main () {
int i = 10;
5 int j = 5;
/* First expression is evaluated and its result is discarded */
1.4. C OPERATORS 95
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;
}
✆✌
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
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
✆✌
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
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
✆✌
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
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
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
✞
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
20 return 0;
}
✆✌
✞
64 1 64 32
✆✌
In above example, bit shift of ‘cb’ does not affects the value of ‘ca’ any way.
9 main () {
printf ( " Does myfile . au exist : % s \ n " ,
11 file_exists ( " myfile . au " ) ? " YES " : " NO " ) ;
}
✆✌
✞
Does myfile . au exist : NO
✆✌
str1 s i m p l e
str2 s i M p l e
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.
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
int main () {
4 float a ;
int main () {
4 int a ;
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’.
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.
✞
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
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.
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 };
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
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
✆✌
y = ((5 + 3) − (4%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
✆✌
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
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
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
✆✌
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
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
✆✌
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 >
✞
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
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
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;
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 .
✆✌
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 .
✆✌
✞
# 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 >
int grade ;
5
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
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 }
✆✌
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.
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 >
9 }
✆✌
✞
1 # include < stdio .h >
# include < stdlib .h >
3
Product of i =4 & j =8 is 32
Product of i =5 & j =10 is 50
✆✌
✞
1 # include < stdio .h >
# include < stdlib .h >
3
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
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
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
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 >
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
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
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
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.
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
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
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 main () {
6 char MainStr [100] , SubStr [100] , CnF ;
16 if ( CnF == 0)
printf ( " Both strings are same .\ n " ) ;
18 else
printf ( " Entered strings are not equal .\ n " ) ;
20
return 0;
22 }
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
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 >
✞
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 >
✞
1 # include < stdio .h >
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 ! "
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];
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
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
✆✌
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
✞
executable . exe " This is my name " " "
This
is
my
name
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 ;
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
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 >
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 >
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 >
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
*((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 >
✞
# include < stdio .h >
2 /* Prototype is disabled . */
// void swap ( int * u , int * v ) ;
4
char myFunc () ;
4
✞
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
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
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
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
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 >
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
✆✌
7 } else {
return recFunc ( i - 1 , j + 1) ;
9 }
}
11
12
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
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 >
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 >
/* Function pointer */
13 void * fptr ;
/* Close Library */
31 dlclose ( myLib ) ;
33 return 0;
}
✆✌
✞
called bar function from dll .
✆✌
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
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 }
....
✆✌
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];
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
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 }
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
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 ’.
✆✌
13 wint_t c ;
while (( c = fgetwc ( in ) ) != WEOF )
15 putwchar ( c ) ;
fclose ( in ) ;
17
return EXIT_SUCCESS ;
19 }
✆✌
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 ;
return (0) ;
11 }
✆✌
✞
Hours since January 1 , 1970 = 405089
✆✌
Another example is
✞
1 # include < time .h >
# include < stdlib .h >
3 # include < stdio .h >
✞
1 # include < stdio .h >
# include < stdlib .h >
3
}
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
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 >
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 >
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”.
7 int main () {
int j ;
9 j = compare (2 , 4) ;
printf ( " : - > % d .\ n " , j ) ;
11 return 0;
}
✆✌
✞
: - > 4.
✆✌
3 # define MAXARGS 3
int var_arg () ;
5
int main () {
7 var_arg (1 , 2 , 3) ;
return 0;
9 }
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
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
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) ;
19 int main () {
int i ;
21 double ic ;
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
# define SQUARE ( X ) X * X
1.10. PROCEDURES & FUNCTIONS 201
# define SQUARE ( X ) X * X
4
/* x =2 */
10 printf ( " x = % d \ n " , x ) ;
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.
✆✌
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
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 >
17 int main () {
init_fcn ( age , int ) ;
1.10. PROCEDURES & FUNCTIONS 207
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 >
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
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 "
return 0;
8 }
✆✌
✞
String ’This ’ = integer 2280640.
✆✌
✞
1 # include < stdio .h >
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 () {
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.
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
main () {
9 int i = 5 , j = 2;
func (& i , & j ) ;
11 printf ( " % d % d " , i , j ) ;
return 0;
13 }
✆✌
✞
25 , 4
✆✌
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
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
}
✆✌
✞
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
✆✌
✞
1 # include < stdio .h >
# include < math .h >
3
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.
A simple example is
✞
1 # include < stdio .h >
# include < math .h >
3
Square Root
sqrt () returns the square root of a given value. Mathematically it is represented as
√
y= i
A simple example is
✞
1 # include < stdio .h >
# include < math .h >
3
222 Basic C
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.
A simple example is
✞
1 # include < stdio .h >
# include < math .h >
3
✞
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.
A simple example is
✞
1 # include < stdio .h >
# include < math .h >
3
✞
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
round(1.6)
round(1.4)
1.4
bc b b bc
1.6
0 1 2 3
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
f = ±m × b±e
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.
e-Line
−2 −1 0 1 2
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
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
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
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.
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
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)
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’.
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.
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 >
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
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
6 31
✆✌
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.
10 0 0 0 20 0 0 0 15 0 0 0 2 0 0 0
✞
# 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
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
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
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
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
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
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
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
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 }
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
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
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
✆✌
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:
# 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
✆✌
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()
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
}
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 >
7 int main () {
char * label = " Allora Caves . " ;
9 PrintIt ( label ) ;
return 0;
11 }
✆✌
The output is
✞
Allora Caves .
✆✌
✞
1 # include < stdio .h >
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
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
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 >
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
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
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
!
!
✆✌
ax + by − k = 0
u = [a, b, −k]
ax + by − k =0
cx + dy − l =0
Then two vectors of these two algebraic equations are u and v respectively as
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
✞
0 1 2 3
1 2 3 4
✆✌
In C, arrays, vectors and matrices are defined in same ways.
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
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.
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;
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
i[ ] 10 20 30 40 50
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;
}
✆✌
i[ ] 10 20 30 40 50
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
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;
}
✆✌
✞
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 ) () ;
✆✌
✞
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
✞
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 :
✞
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).
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?
✞
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).
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 :
✞
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 ).
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.
&k
0×50 0×51 0×52 0×53 0×54 0×55 0×56
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
✞
i is 20
i is 20
✆✌
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
∗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 >
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:
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 >
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 }
✞
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
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
A r u n \0
0×40 0×41 0×42 0×43 0×44
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
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
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 >
✞
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 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 }
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 >
11 return ch ;
}
13
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";
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 >
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
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
15 int main () {
/* Structure variable */
17 struct s myS ;
2.2. POINTER 297
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.
*(*(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
✆✌
✞
1 # include < stdio .h >
/* Defined two arrays to be copied */
3 char A [80] = " Lucknow is capital city . " ;
char B [80];
5
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
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 >
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 * 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 }
33 }
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 }
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 */
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
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 >
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 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
✞
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 .
✆✌
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 .
✆✌
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 >
∗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.
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) 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
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.
✞
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 >
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
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.
10 p ++;
}
12 return 0;
}
✆✌
✞
: - > 50
: - > 99
: - > 3490
✆✌
Another example, using pointer for addition of numbers in an array.
✞
1 # include < stdio .h >
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
1
1 1 1 1
bits
0 0 0 0
−1
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
0 0 1 1 1 0 0 1
bits
Decimal digit 9
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++)
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
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
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]
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]
x
330 Array & Pointer
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.
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
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
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
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
3 int main () {
2.2. POINTER 339
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
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
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
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
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
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.
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’.
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 *(*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
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
✞
1 # include < stdio .h >
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
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
✞
1 # include < stdio .h >
3 double * p ( double * j ) {
* j = 10 * (* j ) ;
5 return j ;
}
7
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)();
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
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 *(*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())();
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
✞
1 # include < stdio .h >
int * p ( int * j ) {
9 j = myf (* j ) ;
return j ;
11 }
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
9 }
int (*p())[ ];
It constructs a function ‘p’ which returns a pointer value. The return pointer points to
an array of integers.
myf 0×20
0×30 0×31 0×32 0×33 0×34 0×35 0×36 0×37
int * myf () {
5 return j ;
}
7
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
3 struct Struc {
int i ;
5 char ch ;
};
7
✞
1 # include < stdio .h >
# include < string .h >
3 # include < stdlib .h >
/* 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.
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
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
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
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
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
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 >
}
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 .
✆✌
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;
}
✆✌
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 ;
Char in position 1 is
Char in position 2 is
✆✌
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
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
14 len = ftell ( fp ) ;
fclose ( fp ) ;
16
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
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 }
✆✌
3 int main () {
FILE * fp ;
5 int ch ;
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
✆✌
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 >
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;
}
✆✌
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
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
int main () {
5 int res ;
char * str1 , * str2 ;
7
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
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
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 }
4 int main () {
int res ;
6 char * str1 , * 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
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
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 >
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
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 >
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 >
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
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 () {
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
✆✌
✞
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 ...
✆✌
6 int main () {
✞
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.
15 return 0;
}
17
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 ;
}
✆✌
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 >
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 >
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
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
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
✞
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
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
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
st st++
val fl
A working example is
✞
# include < stdio .h >
2
struct Func {
4 int val ;
float fl ;
6 };
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 };
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
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 ;
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
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 ;
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 . */
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 ;
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
3 struct TreeData {
int x_old ;
5 int y_old ;
int x_new ;
7 int y_new ;
int val ;
9 };
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.
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
✆✌
3 struct st {
int i ; /* First element */
5 int j ; /* Second element */
};
7
15 int main () {
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 ;
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 ;
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;
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 - >| */
return 0;
23 }
✆✌
✞
data . c : 3
data . d : 201170739
✆✌
data.d
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
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
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
Stack (0 to 3)
Low count High count
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
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
3 # define MAXSIZE 5
struct stack s ;
11
void main () {
19 int choice ;
int option = 1;
21
s . top = -1;
23
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
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
MyClass myNewClass () {
9 MyClass this = malloc ( sizeof * this ) ;
this - > variable = 0;
11 return this ;
}
13
3.3. DATA STRUCTURES 433
25 int main () {
MyClass obj = myNewClass () ;
27 myNewClassSe t ( obj ) ;
printf ( " % d " , obj - > variable ) ;
29 myNewClassDe l et e (& obj ) ;
return 0;
31 }
✆✌
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
void f1 ( void ) {
7 struct x {
int i ;
9 }; /* redeclaration ! */
}
11
17 void f2 ( void ) {
/* valid statements */
19 p = & s_x ;
* p = func () ;
21 s_x = func () ;
}
23
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
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
✆✌
4 struct myNode {
int data ;
6 struct myNode * nextPtr ;
};
8
20 int main () {
3.3. DATA STRUCTURES 437
myP
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
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
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
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
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 };
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 };
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
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
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 };
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
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
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.
6 int val ;
};
8
* child node . */
9 struct TreeData {
int x_node ;
11 int y_node ;
int x_child_node ;
13 int y_child_node ;
int val ;
15 };
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
view (& td , fp , 1 , 1) ;
111 fclose ( fp ) ;
return 0;
113 }
✆✌
4 Miscellaneous
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
✞
# include < stdio .h >
2 /* Must include to see " errno " */
# include < errno .h >
4
✞
# 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 . */
}
✆✌
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.
# ifdef __cplusplus
5 extern " C " {
# endif
7
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.
✞
1 # ifndef MYFUNC_H
# define MYFUNC_H
3
# ifdef __cplusplus
5 extern " C " {
# endif
7
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.
✞
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 int main () {
void * myLib ;
5.3. LOAD LIBRARY DYNAMICALLY 463
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 ) ;
✆✌