C-Language Programming Guide
C-Language Programming Guide
This book softcopy is available in [Link] website, to download the file, search through keyword
‘cfamily’, along with this book, you get 500 exercise programs list on C,C++, Java programming.
This pdf file(s) designed for 2-sided print-copy (Xerox copy).
I request you to rate the C-Family on Google review.
C-Family 2 Preface & Index
Functions 134
Pointers 155
operators in pointers 155
arrays & pointers, passing array to function 159,160
call-by-value vs call-by-reference 172
2D Arrays 195
Recursion 230
C by Examples
A complete reference material on C-language programming
About C
C-language is an ideal programming language and a perfect combination of power and flexibility. Though
it is a high-level language, it has low level features as well as easy interaction with hardware and OS. Even
assembly language code can be mixed in it. It is accepted as a good system programming language.
Powerful OS like UNIX was developed using C.
‘C’ is widely used in the software industry for both system and application side development. C is the
primary subject in computer science. It lays good foundation in programming and eases the learning of
any advanced courses that are to follow. So, it has been added in every branch of arts, science, and
engineering as part of curriculum. Every graduate student is going to face C, C++, DS, Java, Python and
Oracle in the first & second academic years.
I am grateful to all the students, friends, staff who helped me making this material. This book is
advisable to learn the logic and programming skills for beginners. For any suggestions contact me on
[Link]@[Link]
by Srihari Bezawada
since 1999
C-Family Computer Education,
#40-9/1-26, Vasayva Complex,
Dr. Samaram Hospital Lane,
Benz Circle, Vijayawada-10,
9440-030405, 8500-117118.
C-Family 5 Computer Basics
Following example shows how to convert decimal number 13 into its binary form.
Continuously divide 13 with 2 and collect the quotients and remainders, the collection of remainder forms a
binary number, this is as given below.
13 Remainders
13 / 2 1
6 / 2 0
3 / 2 1
1 / 2 1
0
Thus collection of these remainders from bottom-to-top forms a binary number ( 1310 11012 )
Binary to Decimal Conversion
Multiply all digits(bits) of N with 20,21,22,23,24… from right-to-left, the sum of all such products forms a
decimal number. Following example explains how to convert binary number 1101 to its decimal 13.
Hexa decimal System: The base of this system is 16, and we have 16 symbols from 0 to 15, the
symbols are 0,1,2,3,….9,A,B,C,D,E,F (10A, 11B, 12C, 13D, 14E, 15F).
This system mainly used to represent binary number in simple readable form of digits & alphabets.
As we know, binary system is very difficult to follow, because everything is in 1 or 0. So we represent binary
numbers in hexadecimal system for simplicity. Actually, Hexadecimal system resembles the binary values.
Here we divide a binary number into 4-bit groups, where each group contains exactly 4bits and each group is
represented in hexadecimal value. Let us take a sample binary number: 1101100111000011
This binary value is divided in 4-bit as 1101-1001-1100-0011, and is taken in hexadecimal system as D9C3.
Memory Measurements
Memory constituted in the form of bytes, where each byte consists of 8bits and the measurements are
1 bit = 1 cell the single bit or cell can hold either 1/0
8 bits = 1 byte
1024 bytes = 1 kilo byte (1kb)
1024 kilo bytes = 1 mega byte (1mb)
1024 mega bytes = 1 giga byte (1gb)
1024 giga bytes = 1 tera byte (1tb)
1024 tera bytes = 1 peta byte (1pb)
eg1) The binary value 1101 is stored in a byte as ( remember, 1 byte = 8 bits )
0 0 0 0 1 1 0 1
th th th th th rd nd st
8 bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit
The computer automatically adds zeros in front of 1101, this is like 00001101.
eg2) The binary value 1001101 is stored in a byte as
0 1 0 0 1 1 0 1
th th th th th rd nd st
8 bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit
Overflow error: we can’t store more than 8bit value in 1byte memory, it causes over-flow error.
Here leftmost bits are omitted (truncated). eg: If we store 12bit value like 1100-1101-1001 in 1byte, then it
holds only right most 8-bits 1101-1001 and the left most 4-bits 1100 are truncated.
C-Family 7 Computer Basics
1 1 1 1 4
This value 1111 is equal to 2 -1 in binary system
th rd nd st
4 bit 3 bit 2 bit 1 bit This is maximum value that can be stored in 4bits of binary system
Some people raise a doubt about how the binary value 1111 is equal to 2 4-1
we already know, how to convert binary value to decimal, so by converting 1111 into decimal, we get 24-1.
+ve sign
0 0 0 0 1 1 0 1
th th th th th rd nd st
8 bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit
-ve sign
1 0 0 0 1 1 0 1
th th th th th rd nd st
8 bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit
Binary addition
Addition of binary values
X 0 0 1 1
Y 0 1 0 1
X+Y 0 1 1 10
When we add 1+1 we get sum as 0, and carry as 1, so result is 10
don’t call this result as ten, call it as one - zero.
carry 1 1
Carry 1 1 1 1
X 1
X 1 1 0 1 X 1 1 0 1
Y 1
Y 1 1 1 1 Y 1 1 1 0
Z 1
X+Y 1 1 1 1 0 X+Y 1 1 0 1 1
X+Y+Z 11
Binary subtraction
In computer, subtraction is done like addition using 2’s complement method, this is truly simple and fast.
The normal subtraction of two values takes much time; here we may need to check & barrow from next
digits. For example, subtraction of 3456 - 0999. Here first, we try to subtract last digits 6-9, but here 6<9,
so we need to barrow from next digits. In this way, we have to look-up and barrow from next position digits.
This process takes much time and complex. The best solution is, 2’s complement method.
Evolution of languages
We have three types of languages [Link] language, [Link] language, [Link] level language.
Programs are written using these languages.
A) Machine Language (binary/low level language)
It is treated as first generation language, used during development of computer in 19th century. In this
language, the data and instruction of programs were written in terms of binary symbols (1&0’s), even input
and output were given in binary codes, as the computer understands the instructions only in ones and zeros.
For example, the instruction 9+13 is in binary form like 0010 1001 1101. Here, the first 4 bits represents the
code of ‘+’ and remaining 8 bits are 9 & 13. This language is also called binary or low-level language. Actually,
this language is difficult to understand, remember and writing programs in binary codes, it leads to a lot of
typing mistakes, because everything is 1&0s. This problem led to the invention of assembly language.
B) Assembly Language
this is somewhat better than binary language. Here, symbolic names were provided for every binary codes
of machine language. The names such as add, sub, mul, div, cmp, etc. So, programmers can easily
understand and write instructions using these names instead of binary 1&0’s. For example adding 4 & 6 in
8088 assembly language as
mov ax,4;
mov bx,6;
add ax,bx
However, the main drawback of assembly language is, a large set of instructions are needed to be written
for simple tasks like addition of two numbers. It supports only small programs if the code is <1000 lines,
otherwise difficult to manage the code. Moreover, assembly differs from one to another machine. Some
people consider Assembly language also a machine language since the assembly codes resembles the
machine codes.
C-Family 10 Computer Basics
Brief History of C
In 1960’s, there was a need for general purpose programming language and the available ones were of
specific-purpose only. For example, COBOL was meant for business applications; similarly FORTRAN was
extremely small and suitable only for scientific applications. Instead of being small, simple and specific, the
CPL was intended to support wide range of applications in all sectors; thus, the demand for a general-
purpose language led to the invention of CPL (Combined Programming Language). However, its heavy
specific features made it difficult to program. Its drawbacks were eliminated, simplified and further
developed by Martin Richards and named as BCPL (Basic CPL). Still it had some complex & difficult features
of CPL and these difficulties were simplified by ken Thompson and named it as ‘B’.
Later while developing UNIX operating system in 1969, ken Thomson faced several problems with the B
language; here B was used for programming while making UNIX software. Dennis Ritchie modified the B
language to overcome its limitations to suit all needs and renamed it as C. Of course, the development of
UNIX using C language made it uniquely portable and improvable; Finally, C was released in 1972. Dennis
Ritchie is a research scientist at Bell Telephone Laboratories in U.S.A. Brian Kernighan also participated while
making the definitive description of the language. Therefore, the C is also referred as ‘K&R-C’.
Features of C-Language
A) C is a small & compact language: It has small number of keywords and symbols. Therefore, it provides
easy & compact programming. The size of software is also less compared to other language and it has good
library functions.
Subroutine: this is also called function or sub-program or procedure or method. This feature is to divide a
big program into several reusable segments called sub-programs, each with the all necessary data and
instructions to perform a certain task. Thus, this collection of sub-programs makes the entire program.
D) C is a portable language: The word portable means easy to carry or transfer, here the portability refers
to the ability of a program to run on different environments (hardware or operating systems).
As ‘C’ became powerful, it had provided different version of C-compilers for different operating systems.
A C-program written in one platform can be portable to any other platform with few/negligible
modifications. For example, a program written in UNIX operating system can be easily converted to run in
WINDOWS or DOS and vice versa.
E) C has flexible coding style: Unlike other languages (COBOL, FORTRAN), C provides a freedom to the
programmer while coding the program. We can write the code without bothering about the alignment of
instructions. The C compiler can recognize the code even when the program is not aligned or typed properly.
In other words, we can use more spaces, empty lines in between instructions (tokens), or we can type
several instructions in one line.
F) Widely Acceptable: It is suitable for both system and application side programming. It frees the
programmer from traditional programming limitations. It empowers the programmer to develop any kind of
applications. Thus, accepted by almost all users and became the most popular language in the world. In fact,
many of the software available in the market are written in C.
G) C is a case sensitive language: In C, an upper-case alphabet is never treated equal to the lower-case
alphabet and vice versa. All most all keywords and predefined routines of C languages use only lower-case
alphabets. Therefore, it is very simple to type in only one case. Of course, some user defined symbols
(identifiers) can be typed in upper case to identify them uniquely.
C-Family 12 Computer Basics
Operating System
The term O.S refers to a set of programs that manages the resources of a computer. The resources of
computer include processor, main-memory, disks, and other devices such as keyboard, monitor, printer that
are connected to it. It also provides a good interface to the user. The interface provided by the O.S enables
the user to use the computer without knowing the details of the hardware. So, interface hides the
underlying working of a computer. The main jobs of O.S are memory management, process management,
disk management, I/O management, security, and providing interface to the user …etc.
Currently, the widely used operating systems are MS-DOS, UNIX, and WINDOWS. DOS is a simple operating
system largely used in PCs. Unix, Linux, Mac, Windows on the other hand used variety of computers such as
mainframes, servers, graphics workstations, supercomputers, and also in PCs.
When a user runs a program (app) in the computer, the operating system loads the program into main
memory (RAM) from the hard-disk, and then executes the instruction by instruction with the help of
processor. The processor can take & execute only one instruction at a time. So, this loading and executing
instructions is done under the control of OS. Thus, OS executes our programs with the help of hardware. OS
is the main responsible for all these things and also makes the computer in working for other tasks.
The relation between hardware, operating system, user-program, and user can simulate with a banking-
system such as bank, employee, transaction and customer. The hardware as a bank and O.S as a bank
employee, who works dedicatedly to organize all transactions of a bank, whereas the user as a customer and
user-program as a transaction, the user submits his program just by giving a command to the computer; the
responder, the O.S, takes up the program into main memory and process the instructions on the hardware
under its control. The following picture shows the layers of interaction between user and the computer.
User Customer
User program Transaction
Operating system Bank employee
Computer hardware Bank
C Character set
It is a set of symbols called characters, which are supported by the C-language. C supports all most all
symbols which are provided in the keyboard
Lower case alphabets (a-z), Upper case alphabets (A-Z)
Digits (0-9)
White space (‘ ‘)
Math symbols ( + , - , * , / , % < > = …etc )
Special symbols like ,- *+ () ! & , “ \ …etc )
C Keywords
Like English language vocabulary, C has its own vocabulary called keywords; thus, Keyword is a reserved
word, which has specific meaning in C, and it cannot be used for other purpose, using these keywords, the
programs are constructed. C has the following standard set of 32 keywords.
if, else, switch, for, while, break, continue, goto, auto, register, extern, static, volatile, return, enum, void,
char, int, long, short, float, double, signed, unsigned, case, const, default, do, union, sizeof, typedef, struct;
Note: All keywords should be written in lower case. Depending on the compiler/vendor, few additional
keywords may also exist.
C-Family 13 Computer Basics
Tokens
Let the expression ‘x+y’. It has three tokens ‘x’, ’y’ and ‘+’. Here x, y are called operands, and ‘+’ is called an
operator. The compiler splits all the instructions into individual tokens for checking syntax errors. Splitting
expression into tokens and checking is known as parsing.
Now token can be defined as an elementary item in the program, which is parsed by the compiler.
Token can be a keyword, operator, identifier, constant, or any other symbol; For example,
a+b // this expression has 3 tokens: a , b , +
a<=b // this has 3 tokens ‘a’, ‘b’, ‘<=’ ( here ‘<=’ is a single token )
c++ // this has 2 tokens c , ++ ( here ‘++’ is a single token )
if(a<b) // it has 6 tokens
data
signed int or unsigned int are system dependents, for example, in 16-bit DOS, it occupies 16 bits of memory,
whereas in 32-bit Unix/Windows, it occupies 32 bits of memory. So, they occupy 2/4 bytes based on system.
The keyword signed is an optional word for signed types. That means, even if we do not mention the
keyword ‘signed’, the compiler by default takes as signed types.
For example, the ‘int’ is equal to ‘signed int’ in the C-language.
int a, b, c; is equal to signed int a, b , c;
C-Family 15 Computer Basics
Operators
Operator is a symbol or keyword used to compute mathematical or logical calculations in a program.
C provides rich set of operators for making flexible and simple expressions. Operators are classified primarily
into four categories: arithmetic, relational, logical, and bitwise. Assignment, referencing, de-referencing are
called special operators. Each operator comes under one of the following types.
Unary Operators: These operators are associated with only one operand.
Binary Operators: These operators are associated with two operands.
Ternary Operators: These take three operands to perform an operation.
Note: just go through these operators briefly, we can learn in detailed in rest of the chapters.
A) Arithmetic operators ( + - * / %)
These operators are used to calculate arithmetical sums such as addition(+), subtraction(-), multiplication
(*), division(/) for quotient and modulus division(%) for remainder.
Let us see some of arithmetic expressions. Here a & b are operands
a + b, a - b, a * b, a / b, a%b
Integer division gives only the integer part of the result, that is, the fraction part is truncated (ignored).
For example, the result of 15/2 is 7 (not 7.5). The floating point division gives fractions also (15.0/27.5)
The modulus-division gives the remainder of a division, for example 17%32. Notice that, we cannot apply
modulus-division on floating point values as the division goes on and on till the remainder becomes zero,
therefore, it is meaningless applying ‘%’ on float values. For example, the instruction 15.0%2.0 is an error.
C-Family 16 Computer Basics
B) Relational operators
These operators are used to find the relation between two values. If relation is found to be true then the
result is 1, otherwise it is 0. (The result of this 1 & 0 values is said to be BOOLEAN values).
The operators such as: < > <= >= == !=
C) Logical Operators
These operators are used to combine two or more relations to form a single compound relation.
These operators also gives the result either 1 or 0 (Boolean value)
&& Logical AND operator
|| Logical OR operator
! Logical NOT operator
The operator ‘&&’ works just like the word ‘AND’ in English language.
The operator ‘||’ works just like the word ‘OR’ in English language.
syntax1: relation1 && relation2 eg: if marks1>50 && marks2>50 then student is passed
syntax2: relation1 || relation2 eg: if marks1<50 || marks2<50) then student is failed
syntax3: ! relation !true false
1) When we want two or more relations to be true for one action then we use AND operator(&&),
for example if A>B and A>C are true, then ‘A’ is said to be bigger than B,C.
In C-lang, it is written as: if(A>B && A>C)
here if both conditions A>B and A>C are satisfied, then the operator && gives the result 1 (true).
If anyone of them is false, the result is 0 (false).
C-Family 17 Computer Basics
2) When we want either of one relation to be true for one action, then we use OR operator(||),
for example, If any marks1<35 or marks2<35 or marks3<35 are true, then student is “failed”.
in C program, it is written as if( marks1<35 || marks2<35 || marks3<35 )
if at least one relation is satisfied, the operator || gives the result true. If all are false, then result is false
A B A &&B A||B !A
1 1 1 1 0
1 0 0 1 0
0 1 0 1 1
0 0 0 0 1
E F G
E=F=G=100; // assigns 100 to all E, F, G
100 100 100
A+B=C; // error, not following syntax rules, c value cannot be assigned to A+B
2) B = ++A; // this is equal to given below, first pre-increment and then assignment
++A;
B=A;
result is: A gains 6, B also gains 6
3) B = A++; this is equal to given below, first assignment and then post-increment
B=A;
A++;
result is: B gains 5, A gains 6
4) B = ++A + ++A + A++; this is equal to given below, we have two pre-increments, and one post-increment)
++A; // pre increment, so do first ( here ‘A’ becomes 6)
++A; // pre increment, so do first (here ‘A’ becomes 7 , this is increment of previous value 6 )
B=A + A + A; // add all values (B=7+7+7)
A++; // post increment, so do last (here ‘A’ becomes 8)
Result of A is 8 , B is 21
Note: So first do all pre increments, next process normal expressions, at last do all post increments.
5) B = A++*3 + ++A + 5*++A; this is equal to given below
++A;
++A;
B=A*3+A+5*A;
A++;
C-Family 19 Computer Basics
Note: in modern compilers, this ++ and – – has changed their working style.
* pre increment means: increment & substitute its value
* post increment means: substitute & increment its value
let A=1; the observe following substitutions.
B = ++A*2 + ++A*3 + A++*4 + A++*5 + ++A;
2*2 + 3*3 + 3*4 + 4*5 + 6
G) sizeof():operator gives the size of memory which is occupied by the variable or constant or data type
sizeof(int) 2
sizeof(long int) 4
sizeof(k) 2 // let k is int type variable
sizeof(10) 2 // 10 is int type value
H) Comma operator(,): It is used to separate two or more instructions in the program. It is used in
several contexts in the programming. The actual behavior of comma operator is that, it returns the right
hand side operand value as the result of the expression.
a=2, b=3, c=10; // Here comma works as separator
c=a , b; // it is combination of two instructions “c=a and b”, but ‘b’ does nothing
a = (b, c); // it is also a combination of two instructions, “b and a=c”
Priority 1 () [] -> .
Priority 2 ! ~ +(sign) -(sign) ++ -- (pre incr/decr)
Priority 3 sizeof &(reference) *(de-reference)
Priority 4 * / %
Priority 5 + -
Priority 6 << >>
Priority 7 < <= > >=
Priority 8 == !=
Priority 9 ^ | & ( ORing, ANDing)
Priority 10 && ||
Priority 11 ?: (conditional operator)
Priority 12 = *= /= %= += -= &=
Priority 13 ^= |= <<= >>=
Priority 14 Comma operator (,)
Priority 15 ++ -- (post increment/ decrement)
In the above table, Operators in the same row have the same precedence. Among same precedence
operators, the evaluation takes place from left-to-right side in the expression. Only the assignment & unary
operators are performed from right-to-left. For example a=b=c=d, here first c=d, and b=c , finally a=b;
C-Family 20 Computer Basics
Declaration of variables
The declaration specifies name, size, type and other characteristics of a variable. Before using any variable,
it must be introduced to the compiler about the name, size and type of data it is going to hold.
This introduction is called variable declaration; it involves creation of memory in the RAM and substitution
of logical address (binding) where ever it is used in the program.
Here in the syntax, the symbols “< >” represent user-defined and are compulsory, whereas square brackets
[] represent optional. [This is old style syntax, now a days nobody following this syntax]
The above syntax can be written as: dataType variable1, variable2, variable3…;
For example: int k1, k2=10; K1 k2
Garbage value 10
2 bytes 2 bytes
This declaration creates 2 bytes of memory space for k1, k2 in RAM; Here k1 has not been assigned with any
value, so by default, it contains garbage value (un-known value), whereas K2 has been initialized with 10;
Let us see more examples:
int age, experience; // holds person age and experience
int year; // year of date
float salary; // salary of employee
Note: Some times, this garbage may belong to our current running program itself. When a function is
terminated, its variable’s space is freed and reallocated for next function’s variable. So, in this way the
garbage values come into picture.
C-Family 22 Computer Basics
C++ comment line: C++ supports single line comment, the syntax is
// ……………………………..comment line…………………………………….
The C++ is a superset of C, hence, we can compile C programs on C++ compiler, hence, we can use C++
comment lines in C programs (of course i myself used this comments during explanation of things).
C-Family 23 Computer Basics
Functions
In general speaking, in our real life, several people are required to accomplish one task with each one of
them doing one’s specialized sub task. Similar to this, a programmer cannot develop the entire code of one
application; instead many programmers contribute the code in terms of sub programs called functions.
Function is a sub-program that performs a given sub task in a program. Here each function is designed and
written for specific purpose such as calculating power, square root, logarithms …etc; thus collection of such
functions makes a C-program. For example, sqrt() is a function, it gives square root value. eg: sqrt(16)4
The functions are classified into ① library functions, ② user–defined functions
Library functions
These are ready-made functions, designed and written by the C manufactures to provide solutions for basic
and routine tasks in the programming. For example, the mathematical functions pow() & sqrt(), and I/O
functions scanf() & printf (),etc. The vendor of C, supply these predefined functions in compiled form with C
software.
There is huge collection of such compiled functions available in C, hence, these collections are called
functions Library. The library functions-body placed in separate files with name “[Link]” in compiled format
and they are automatically linked to our program at the time of compilation, and these are hidden to the
programmer. (We will see about user-defined functions in functions chapter)
printf(): displays message or output values on the screen, the programs are stored permanently in
secondary storage devices like hard disk and when they are gets executed, loaded from hard disk to RAM
and then instruction by instruction is executed by the processor. Here nothing will be displayed on the
screen while executing a program in the memory, if something wanted to be shown on the screen, we must
add an instruction called “printf()”, which displays data/message on the screen. For example
%5d here 5 is said to be maximum width of output value which we want to show on the screen.
if width > output-value size then spaces added by the printf() statement.
if width < digits in value then no spaced added, it prints normally (here ignores the width).
For example,
printf(“%7d”, 523); BBBB523 // Here B means blank space, added by printf()
printf(“%02d”, 7234); 7234 // here width < digits in value, so prints normally ( no affect )
scanf(): used to read input values from keyboard, here user has to feed/enter values in the keyboard
while running a program, based on input values, the output is displayed. The scanf() waits for user
response until he/she enters some values from the keyboard. ie, pauses the program execution until user
enters input values with the end of input “enter-key”. When enter-key is pressed, then the program
resumes its execution. For example,
program keyboard
Let 34,28 are the input of A,B in the following example, then how the user should be given in the keyboard
scanf(“%d%d”, &A , &B); 34 space 28 ⤶ // space is the default separator between two values
scanf(“%dQQQ%d”, &A , &B); 34QQQ28⤶ // here QQQ is the separator for 34 and 28 values
scanf(“%d/%d”, &A , &B); 34/28⤶ // here slash(/) is the separator or 34 and 28 values
Therefore, in a C program there must be at least one function must be exist, that is main(); its execution
starts by operating system when user runs the program. So, the main function is called by the operating
system which is indirectly by the user, for example, when u press F9 or F10 in IDE;
ine1: In this line, the comments are added about program, ie, the purpose of program, input/output of
program, who & when has written, etc. Writing comments is a good programming practice.
However, this is optional. Compiler ignores comment lines.
line2: Here header files of library functions and other files are included. For example “#include<math.h> for
math functions, #include<stdio.h> for I/O functions ….etc;
Note: these files contain syntax of library function to check error at call statements.
line3: “void main ()” represents starting point of program, it tells, the main process begins here.
line4: variables are declared at the beginning of program block, and when this line is executed, space
is allocated for variables in the RAM.
line5: the input statements are used to accept values from the keyboard and other terminals.
line6: Here process statements specify the processing of input data.
line7: here the output statements are used to show output on the screen or other terminals.
Note: the opening and subsequent closing braces {} defines a block; as per C syntax rules, the instruction
must be given inside block; all instructions must be terminated by “;”
Note: In condition place, the value non-zero is taken as true, whereas, zero is taken as false
C-Family 32 Computer Basics
main() Output
{ long int k;
printf("\n size of int is %d byte" , sizeof(int)); size of int is 2 byte
printf("\n size of float is %d byte ", sizeof(float)); size of float is 4 byte
printf("\n size of k is %d bytes" , sizeof(k)); size of k is 4 bytes
printf("\n size of 10 is %d bytes" , sizeof(10)); size of 10 is 2 bytes (10 is int-type)
}
File menu: this menu-driven facility used to handle file operations such as opening a new file, or opening an
existing file, saving a file, etc.
Edit menu: this is used to copy, cut, and paste a group of selected lines.
Compile menu: to create object files, making executable files, linking a program….
C-Family 33 Computer Basics
B) Compiling & Running: compilation process has two stages called compiling + linking
In compilation stage, it checks the typing and syntax errors, after rectifying them, it creates object file, which
is semi executable file. Here each function compiled independently and code is generated separately as they
are in source file. Later linker links all library and user-defined functions together to form a single executable
file. For example, main() function with printf() as shown in the above examples. The following figure shows
how they are compiled and linked to the program.
C program file.
let file name is “sample.c”
Compiler software
Library functions
Linker Software
are attached here
Executable file
“[Link]”
C) Compiler vs Interpreter
Interpreter is a translator, which translates and executes our program. It translates one line at a time and
immediately executes on the machine. It translates line by line and executes instantly on the machine. So, it
also called instant compiler. Whenever we run the program, the interpreter translates and executes, if we
run more times, more translations it takes. It seems to be unnecessary translating same program again &
again in every use. This redundant translation leads to wastage of CPU time and other resources.
Actually, interpreter is used for single-use applications like queries, commands, to check spellings in word
processing, language translators, internet browsing, etc. The web-sites are coded in the form of html, css,
etc and these files are downloaded and interpreted by the browsers, web browsers are nothing but
interpreters. So, for single use applications interpreter is the choice.
Compiler translates line by line and stores into “.exe” file to execute later time, thus instead of executing
each line instantly on the processor, it stores into .exe file. Now this file contains all machine code
instructions of our C-program’s source file. This file can be executed directly on the machine whenever we
want, while running this .exe file, the compiler is not required. So here, no translation takes place again &
again in every use. The interpreter doesn’t create “.exe” file, so in every use translation is required.
Some kind of applications needed to execute regularly like calculator, business accounting, games, etc.
Here compiler is used to generate machine code file, so that, such file can be executed at any time without
translating again and again.
Conclusion: compiler is the choice for regular use code, whereas interpreter is the choice for single use code.
For single use applications, it is un-necessary creating machine code file.
Type casting
Process of converting a value from one type to another type is called type casting. In C, the type casting is
done in two ways. ①Implicit type casting (automatic casting) ②Explicit type casting (manual casting)
Representation of Constants in C
In programming, Data is represented in two ways in terms of constants and variable data. Constants are
represented in special manner by adding format string or other symbols to the value. For example, ‘10L’ is
long int type, 10F is float type..
Automatically, compiler understands some types of constants in the program. For example, the constant ‘10’
is considered as int-type, 34.55 as double-type, ‘A’ as char-type. These are default types and automatically
understand by the compiler. But some constant types are needed to specify explicitly along with format
string. The following list explains about all constant types. Do not use other symbols like comma, spaces,
quote, etc while specifying constants.
C-Family 37 Type Casting
integer Constants
A collection of one or more digits with or without a sign referred to as singed int constants. This is the
default type for integral values.
eg. 5, 256, 9113, 6284, +25, -62, etc are valid signed integers.
Similarly, to represent unsigned int, the format string ‘u’ or ‘U’ is suffixed to the value.
eg. 67U, 43U, 4399u, 45u are valid unsigned integers.
Note that, -3428u is also a valid number. Here this -3428 is converted into equivalent unsigned integer
62108. Because, here the sign bit is also considered as data bit. (But this style is not recommended)
Some invalid declaration of integer constants is:
15,467 $25,566 4546Rs
long integer constants
for the long integer constants, the format string ‘l’ or ‘L’ is suffixed to the value.
eg: 2486384L –123456L 5434545l –34545l are valid long int constants
893434lu -3Lu … etc are valid unsigned long integers.
Octal int/long integer constants
for the octal integers, zero is prefixed before the value. (0 is like octal).
eg: 0123, 0574, 01, 046342L etc are valid octal integers.
0181, 09, 12, etc are in-valid octal integers. (In octal system 0-7 digits are used)
Hexadecimal int/long integer constants
in the hexadecimal number system, the symbols 0, 1, 2, 3 … 9, A, B, C, D, E, F are used.
(Total 16 symbols are used; because, the number system’s base is 16)
The symbol “0x or 0X” is prefixed before the hexadecimal number.
For example: 0x1, 0x123, 0xa5, 0xfldb, 0x0, 0xABC, 0xflc etc are valid hexadecimals.
character constants
To specify a character constant, we must enclose the character within the pair of single quotes.
eg. ‘A’ ‘z’ ‘s’ ‘8’ ‘+’ ‘;’ etc
string constants
It is a collection of characters enclosed within double quotes, used to represent names, codes, abels, etc.
eg: “Hello! Good morning!” “Magic mania” “A” “123” “A1” “#40-5-8A” “C-Family”
float constants (Real numbers)
We can specify the real numbers in two different notations, namely general and scientific notation.
Here the format string ‘f’ is attached at the end of value.
In normal representation: 3.1412f -25.62f 98.12f -045632.0f 1.f 9.13f
In scientific exponential representation: the syntax is [-][Link][+/-]ddd where d is any digit.
2.32e5f (means 2.32 x 10^5 i.e. 232000.0)
12.102e-3f (means 12.102 x 10^-3 i.e., 0.012102)
-2. 165e6f (means -2.165 x 10^6 i.e., -2165000.0)
3.68e3f (means 3.68 x 10^3 i.e., 3680.0)
double constants: This is the default type for real numbers (floating point values).
eg: 1.2 45.3 4.39393 349.34899034
45.4e15 44.54e4 (‘l’ or ‘L’ is option for double)
long double: for the long double, the format string ‘l’ or ‘L’ is used.
eg: 3.14L
314.41 (Equivalent to 314. 0L)
3.68e3L (Means 3.68 x 103 i.e., 3680.0L)
C-Family 38 flow charts
Flow chart
It is a pictorial representation of flow of a program, which illustrates the sequence of operations to be
performed to get the solution of a problem. It is often used as a visual planning tool, how the control to be
moved from one point to another point to get a solution. It is like drawing a building plan before
constructing a building.
Flowcharts are generally drawn in the early stages of formulating computer solutions. It facilitates the
communication between programmers and business people. It plays a vital role to understand the logic of
complicated and lengthy problems. Once the flowchart is drawn, it becomes easy to write the program in
any high-level languages. The following mathematical symbols are used to represent specifications with
directions to indicate the flow of control.
Start/stop a program
Predefined actions
File
Looping
C-Family 39 flow charts
Algorithm
In mathematics and computer science, an algorithm is a finite set of computational instructions that carry
out a particular task, which takes input and produces desired output. In simple words, it is step-by-step oral
explanation of logic how to construct instructions in a program; here English & math symbols are used to
explain logic in words
Flowchart depicts how the control to be moved in the program from one point to another point to get a
solution, whereas algorithm tells step-by-step explanation how to construct instructions in a program.
This is an independent method to explain the logic regardless of programming language used by the
programmer. Here English and math symbols are used to explain the logic. People write algorithm for
complex and complicated tasks to explain the logic in words, for example, sorting algorithms, searching
algorithms, shortest path in network …etc. Any algorithm follows,
1. Describes the input and output
2. Describes the data entities with purpose (variables)
3. Explains process in step by step using English and math symbols
4. Add comments at every step what it does, use square brackets [ ] for comments
5. Each instruction is clear and unambiguous (definiteness)
6. The algorithm terminates after finite number of steps
Note: there are no standard rules and regulation to implement algorithm/flowchart, so one can implement
one’s convenience but ensure that other must be understood it.
Flow chart to find big of two numbers Algorithm to find big of two numbers
Start
step1: let us take a,b as integer type variables
step2: let us take ‘big’ to store big value
read(a,b) step3: [ scanning input from keyboard ]
read(a,b)
step4: [ finding big of 2 numbers ]
if a>b if(a>b) big=a
else big=b;
true false
step5: [ printing output ]
big=a big=b
print(big)
step6: [ closing the program]
stop
Print(big)
stop
C-Family 40 flow charts
Start
read(a,b,c)
true false
if(a>c) if(a>b) if(b>c)
stop
start
print(“enter n:”);
read(n)
sum=0;
i=1;
false
if(i<=n)
true
sum=sum+’i’;
i++;
print(sum)
stop
C-Family 41 flow charts
Pseudo code
Pseudo code is a short hand way of describing a program or algorithm in general language syntax rather
than in specific language syntax. Algorithm uses English and math symbols to explain logic in stepwise,
whereas pseudo code uses programming language syntax to explain logic in term of instructions. So pseudo
code resembles the program with general language syntax. Most of the people adopt C or Pascal language’s
syntax and their control structures to describe the pseudo code.
Algorithm is understandable by any nonprogrammer but pseudo code understandable by a person who
knows at least one programming language. So it is a method used to explain the logic between two
programmers. It is easier for programmers to understand the general workings of one program which is
written by another programmer.
Flow chart shows only execution flow (directions), algorithm explains, what are the steps be taken to get a
solution, but it does not give clear explanation of how to write instructions, for example, to swap 2 values in
the algorithm, we write as: swap(a,b). In pseudo code we write as: t=a, a=b, b=t. So, in pseudo code every
step is written in detailed, which is near to programming. So, one can say loosely, pseudo code is nothing
but a program without accurate syntax (syntax is ignored).
[FlowchartAlgorithm Pseudo codeProgram]
Example for Pseudo code: Calculating sum of 1 to n numbers (1+2+3+4…+n)
Control Statements
Generally, instructions in a program are executed sequentially one after the other, in an order in which they
appear in the program. However, in practice, we need to bypass the control over some set of instructions, or
repeatedly process some instructions or to alter some other sequence depending upon the requirement.
For this purpose, special statements are necessary in programming to handle the control accordingly.
C possesses such a handy control statements like if, if-else, switch, while, etc. These statements alter the
normal execution sequence of a program according to our requirement. Therefore, these statements are
called as control statements. These control-handling statements are of two types.
① Conditional control statements ② Unconditional control statements
Control statements
Conditional Un-conditional
Decision Looping
1) if 1) while 1) goto
2) if-else 2) for 2) break
3) conditional operator 3) do-while 3) continue
4) switch case selection 4) return
Decision control statements: These statements change the flow of execution depending on given logical
condition. Used to execute or skip some set of instructions based on given condition.
Loop statements: These are also called iterative statements, used to execute some set of instructions re-
peatedly until a given condition is failed.
Unconditional control statements: These statements unconditionally transfer the control from one location
to another specified location within a program.
if – statement
It is a decision control statement, executes or skips a given set of instructions depending upon the given test
condition. The syntax is
if(test-condition) false
test condition
{ instruction 1;
instruction 2; true
instruction 3; Instruction 1;
Instruction 2
}
Instruction 3
instruction 4; // after “if” statement
instruction 5;
Instruction 4
------ Instruction 5
------ -------------
In the above if-statement, if the test-condition is success (true) then instruction1, instruction2, instruction3
will be executed, later the control comes out of if-body and proceeds with instruction4, instruction5 …etc.
This is shown in the flow chart.
If the result of test-condition is false then control jumps out of if-body and proceeds with instruction 4,
instruction5 …etc. In this case, the instruction1 to instruction3 will not be executed.
C-Family 44 if-else
if( 10 < 5 )
{ printf(“hai ”)
}
printf(“bye”);
}
op: hello bye
In the above, the first condition (10>5) is a true, so printf(“hello”) will be executed, but the second condition
(10<5) is false, so printf(“hai”) will not be executed. The final printf(“bye”) executes irrespective of
if-statements.
This program accepts +ve or –ve integer from keyboard and displays result in +ve.
If user entered –ve value, converts it into +ve by multiplying it with -1.
start
ip: -14 ip: 15
op: 14 op: 15
read(n)
void main()
{ int n;
false
printf(“Enter a +ve/-ve value ”); if n>0
scanf(“%d”,&n); true
true
if(n<0) // if n<0 means, it is -ve
n=n*-1
{ n=n*-1; // if –ve, then converting to +VE
}
printf(“\n Result = %d”, n); print(n)
}
In this program, the instruction n=n*-1 executes when the input is -ve. stop
if-else statement
This is two-way decision control statement, executes either if-block or else-block based on given condition.
If the condition is true then if-block executes, otherwise else-block executes. Let us see the syntax,
if (test-condition )
{
instruction 1; false
Test
instruction 2; // if-block condition
instruction 3;
} true
If the condition is false, the else-block is executed i.e., instruction4 , instruction5, instruction6 are executed
and then control proceeds with instruction7, instruction8 … statements.
if (1>2)
{ printf(“C is simple”);
}
else
{ printf(“C++ is also simple”);
}
}
op: sky is blue C++ is also simple
C-Family 47 if-else
something wrong in this code, fix it something wrong in this code, fix it
if( A<B) a=4, b=4;
printf(“one”); if(a=b) // takes as assignment, not as comparison, so use ==
printf(“two”); printf(“a, b are equal”);
else else
printf(“three”); printf(“a,b are not equal”);
printf(“four”); // take into else-body
printf(“five”); // don’t take into else-body
C-Family 50 if-else
if(m2<50)
bool=0; // if this condition is true, the student failed, so set ‘bool’ to 0
// in the above code, if at least one if-condition is true then ‘bool’ becomes 0, it indicates that, the student failed.
// now result is in ‘bool’ in the form of 1 or 0, so check ‘bool’ value and print “pass” or “fail”
if(bool==1) printf(“passed”);
if(bool==0) printf(“failed”);
-----------------------------------------------------------------------------------------------------------------------------------------------
example 2) finding given input number(N) is in b/w 10 to 20 or not? (finding using bool logic)
ip: 12 ip: 25
op: yes, it is op: no, it is not
k=1; // here ‘k’ is Boolean variable, and assume N is in b/w 10 to 20, so taking k=1
if( N<10)
k=0; // here N is below 10, so not in 10 to 20, then taking k=0
if( N>20)
k=0; // here N is above 20, so not in 10 to 20, then taking k=0
P3) try yourself, if three integers are input through the keyboard, then find at least one value is –ve or not?
try using Boolean logic (do not use logical operators && , || )
ip: 10 20 -30 ip: 10 -20 -30 ip: 10 20 30
op: yes , -ve exist op: yes , -ve exist op: no , -ve exist
--------------------------------------------------------------------------------------------------------------------------------------------
P4) try yourself, check given input time (h, m, s) values are valid or not ? use bool logic.
if seconds and minutes must be <59 and hours must be <12
ip: 10 4 30 ip: 15 4 30 ip: 5 44 30
op: valid inputs op: invalid inputs op: invalid inputs
Nested-If Construct
Construction of one if-statement within another if-statement is called as nested-if. The inner and outer ‘if’
may have ‘else’ part of it. Look at the following different syntaxes of nested-if construct.
The simple form of nested-if statement is
if(condition) // outer if
{
if(condition) // inner if
{
instruction 1;
instruction 2;
---------
instruction n:
}
}
There is no specific syntax for nested-if, we can write in any permutation and combinations, besides, it can
be nested as many times as we need in the program. Let us have some examples,
Demo program finding big of 3 values using nested-if style
// simple nested-if style // nested-if with logical operators
if( A>B ) if( A>B && A>C )
{ if( A>C ) X=A;
X=A; else
else { if( B>C )
X=C; X=B;
} else
else X=C;
{ if( B>C ) }
X=B; printf(“big is %d”, X );
else
X=C; // in this way, by adding logical operators to
} nested-if, we can simplify the code.
printf(“big is %d”, X );
C-Family 56 if-else
Demo finding student is passed or not? Here student has 3 subjects, if he got>50 in all then pass or fail
// nested-if without using logical operators // opposite way comparison
if( A>50 )
if( A < 50 )
{ if( B>50 )
x=”failed”;
{ if( C>50 )
else
x=”passed”;
{ if( B < 50 )
else
x=”failed”;
x=”failed”;
else
}
{ if( C < 50 )
else
x=”failed”;
x=”failed”;
else
}
x=”passed”;
else
}
x=”failed;
}
By using logical operators, we can simplify the nested-if // opposite way comparison
statements. But, this is not possible in all cases. The
above code can be simplified using logical operator as
if( A>50 && B>50 && C>50 ) if( A<50 || B<50 || C<50 )
x=”passed”; x=”failed”;
else else
x=”failed”; x=”passed”;
if( A>B && A>C && A>D) if( A>B && A>C && A>D )
{ X=A; X=A;
} else
{ if( B>C && B>D )
if( B>A && B>C && B>D )
X=B;
{ X=B;
else
}
{ if(C>D)
if( C>A && C>B && C>D) X=C;
{ X=C; else
} X=D;
}
if( D>A && D>B && D>C)
}
{ X=C;
} here, if one condition is true, then rest of the conditions are
Note: even if first condition is true, the computer by passed(not checked). So this is best logic.
unnecessary checks all the remaining.
C-Family 58 if-else
Program finding how many digits exist. Let us assume input value of N lies in between 0 to 99999
ip: 234 ip: 3456 ip: 12234 ip: 3
op: 3 op: 4 op: 5 op: 1
if(x>y)
big=x; single statement
else
big=y;
* As inner if-else statement is single, braces are not required to make into single for outer-if.
Based on this theory, we can remove braces for outer-if also. Let us see following example
if(x>y)
if(x>y)
big=x; single statement
else
big=z;
else single statement
if(y>z)
big=y;
else single statement
big=z;
In this way, in C, any control statement can be taken as single compound statement including nested-if,
thus above entire if-statement can be taken as single-compound-statement.
But sometimes, some people used to give braces for clarity purpose even though they are not required.
Example-3
if(x>y && x>y )
big=x;
else single statement
if(y>z)
big=y; single statement
else
big=z;
Example-4
if( a>0 )
{ printf(“Hello1”);
printf(“Hello2”);
}
else single statement
{ printf(“Hello3”);
printf(“Hello4”);
}
C-Family 61 if-else
if( A>B && A>C && A>D ) if( A>B && A>C && A>D )
X=A; X=A;
else else
{ if( B>C && B>D ) if( B>C && B>D )
X=B; X=B;
else else
{ if(C>D) if(C>D)
X=C; X=C;
else else
X=D; X=D;
}
}
C-Family 62 if-else
Here conditions are evaluated from top to down, as soon as a true condition is found, the instruction
associated with it is executed and the rest of the ladder is bypassed. If none of the conditions are true, the
final ‘else-part’ will be executed. That is, if all other condition tests fail, the final ‘else’ instruction-n will be
performed. If the final ‘else’ is not present, no action takes place.
Although, the above ‘if-else-if’ ladder is technically correct, it can lead to bit confusion to some
programmers. For this reason, the ‘if-else-if’ ladder style also written as
If(condition 1)
instruction 1;
else
if(condition 2)
instruction 2;
else
if(condition 3)
instruction 3;
-----------
-----------
else
instruction n;
Observe here, the nested statements are started in a new
line unlike same line as above said.
C-Family 63 if-else
if(m1<35||m2<35||m3<35) if(m1<35||m2<35||m3<35)
printf(“\n F grade”); printf(“\n F grade”);
else else if(avg>=60)
{ if(avg>=60) printf(“A grade”);
printf(“A grade”); else if(avg>=50)
else printf(“B grade”);
{ if(avg>=50) else
printf(“B grade”); printf(“C grade”);
else }
printf(“C grade”);
}
}
}
The above left side given nested-if cross aligned, however it is readable (because few decisions exist). If the
programmer did not take care while aligning the code properly, it makes un-readable and difficult to debug.
Hence, if-else-if ladder style is always best. If more than 10 alternative decisions exist, the normal nested-if
seems to be awkward and confusion, so the ladder-style is the alternative under any case.
C-Family 64 if-else
These two statements are same with little difference, you can follow whichever you like
void main()
{ int d, m, y, bool;
printf(“enter date :”);
scanf(“%d%d%d”, &d, &m, &y);
bool=1; // let us take date is valid
if(m<1 || m>12 || d<1 || d>31)
bool=0;
else if(m==2 && y%4==0 && d>29) // for February and leap-year checking
bool=0;
else if(m==2 && y%4!=0 && d>28) // for February and non-leap year checking
bool=0;
else if((m==4 || m==6 || m==9 || m==11) && d>30) // for 30-days month checking
bool=0;
if(bool==1) printf(“date is valid”); //finally check the bool and print the output
else printf(“date is in-valid”);
}
C-Family 66 if-else
if - else linking
eg1) In C, if & else are 1:1 type, one else-statement always linked to only one if-statement in the program,
we cannot write one else-statement for two or more if-statements, following example explains it.
if( marks1>50)
if(marks2>50)
if(marks3>50)
printf(“passed”);
else
printf(“failed”);
in above , the else-part joins only to the last if-statement(marks3>50), so we can’t write one else-part to
many if-statements. The solution is, we need to write else-part to every if-statement, this is as
if(m1>=35)
if(m2>=35)
if(m3>=35)
printf(“passed”);
else
printf(“failed”);
else
printf(“failed”);
else
printf(“failed”);
------------------------------------------------------------------------------------------------------------------------------------------------
eg2) In some situations, where the ‘else’ is available to the outer-if and not to the inner-if , in that case, the
inner-if should be enclosed within braces { }, otherwise compiler links outer-else body to the inner-if.
Observe the following example
if(x==1)
if(y==2)
printf(“ x is 1, y is 2 ”);
else
printf(“x is not 1”);
Here, the programmer wrote else-part to the outer-if, but compiler links to the inner-if, to avoid this logical
error, enclose inner-if within braces { }. This is as follows
if(x==1)
{ if(y==2) // now this ‘if’ has no else part of it
printf(“x is 1, y is 2”);
}
else
printf(“x is not 1”);
C-Family 68 if-else
if( 0 ) // false
printf(“ Black ”);
if(x&&y)
printf(“Black”); // if( x&&y ) if( 0 && 1 ) if(false && true) if( false)
if(x||y)
printf(“Grey”); // if( x||y ) if( 0 || 1 ) if(false || true) if( true)
}
C-Family 69 if-else
Switch Statement
Switch is another conditional control statement used to select one option from several options based on
given expression value. This is an alternative to the if-else-if ladder when comparisons found against with
constants. The if-else-if seems to be lengthy and awkward when more comparisons exist. Switch is a good
alternative as its construction is simple and looking comfortable even if more cases found or nested.
However it does not support in all situations in which if-else-if supports. ie, it compares only against with
integral constants. In switch construct, the instructions are divided into case blocks based on logical
condition and any number of case blocks can be defined. Observe the following syntax and flow chart.
* The expression in switch() header should be an integral type value such as char, int, long int.
* The expression value compares with constant-1, constant-2,… etc, if anyone matches then the control
jumps into associated case block and executes all the instructions within it, later comes out by break.
The break throws the control out of switch statement. In other words, keyword break used to come out of
switch after execution of selected case block. However, break is an optional statement. If it is not present at
end of case-block, the control enters into next case block even though its constant value differs.
* The case constants may not be in ascending or descending order. The two or more case constants may be
associated with single block.
* The default block executes when no case is matched. The default is optional block and generally it is used
to handle input errors.
* In case block of switch, we can write any other control statement, sometimes it can be nested
* remember, this is an alternative statement of if-else-if ladder style, but this is used only when comparisons
made against with constants. This is the limitation of this statement.
C-Family 74 switch statement
If no case matches with the given value, then the default block executes and we get “Invalid input”.
Generally, default block used to handle errors like “invalid-input” and other things.
Suppose the input is 4, then the “case 4:” matches and executes printf(“four”). Later control comes out
when break gets executed.
The above program can be written using if-else-if ladder form as shown below.
void main()
{ int k ;
printf(“Enter a digit:”);
scanf(“%d”,&k);
if(k==0)
printf(“zero”);
else if(k==1)
printf(“one”);
else if(k==2)
printf(“two”);
……
else if(k==9)
printf(“nine”);
else
printf(“Invalid input”); // like default block
}
The above two programs generate exactly same result. However, as you might notice that the first program
is easier to write, understand and modify. Structure of switch statement is more readable even if it is nested
2 or 3 times.
C-Family 75 switch statement
switch(N)
{ case 10: printf(“red”); // observe “break” not given
case 20: printf(“green”);
break;
case 30: printf(“blue”);
default: printf(“black”);
}
}
if input: 10 red green (output of case-10 and case-20)
if input: 20 green (output of case-20 )
if input: 30 blue black (output of case 30 and default )
if input: 40 black ( output of default)
if input: 50 black ( output of default )
if input: 0 black ( output of default )
goto Statement
It is used to jump the control from one location to another location within a function. This unconditional
control statement diverts the control to a specified location where the label is mentioned. Using this, the
control can be moved to forward or backward or in any order in the function.
The early high level languages such as ALGOL, FORTRAN were influenced by a combination of if & goto
statements. The goto was considered to be a powerful statement as any problem (program) can be solved
using this. But program becomes complex, if the code is big and many goto statements are used.
As a result this statement fell out of favor some years ago, hence several alternative rich set of control
statements are provided in modern languages such as switch, while, for, do-while, break, continue, and
return. However, for some kind of situations like getting out of nested loops, to solve recursive like programs
using loops, …etc. We cannot get a solution using these rich set, so, goto occasionally has its uses.
Syntax: goto label; // Here, the label is a valid identifier followed by a colon, indicates a location to where
the control has to be jumped using goto. Label name follows the rules of a variable name.
void main()
{ printf(“India\n”);
goto end; //observe here, the control will be transferred to “end”
printf(“American\n”);
printf(“Australia\n”);
end: // here ‘end’ is a label
printf(“Russia\n”);
printf(“Japan\n”);
}
Output: India
Russia
Japan
When “goto end” is executed, the control simply jumps over to label “end” and follows next instructions.
These loop control statements are used to execute some set of instructions repeatedly until a given test
condition is attained. Each loop structure has its own style and provides a convenience to the user. The user
can select any loop control statement in the program according to the requirement and convenience and
there are no specific situational suggestions, which loop to use when and where.
All loop control statements are attached with a test-condition and a body. This body contains one or more
instructions, which are to be executed repeatedly until the test condition becomes false. We can write any
type of instructions or even another control statement with in this body.
If the test-condition becomes false then the control jumps out of loop-body and follows the bottom
instructions “instruction n+1, instruction n+2 ….”
If loop body has only one instruction, the pair of braces {} are optional. This is as said in if-statement.
If loop-body has more instructions exist, they must enclose by pair of braces{}.
The test-condition must fail after certain number of times. Otherwise, it goes to infinite loop.
Don’t terminate loop header with semi-colon, otherwise, the head & body gets separated.
i=10;
while(i>=1) // loop begins here
, printf(“%d ”, i); // printing ‘i’ value on the screen
i--; // decrementing ‘i’ by 1
}
}
Observe semicolon at the end of loop- Let us imagine this semicolon in the next line
header and how it forms as null instruction as loop body
i=1; i=1;
while ( i<=10) ; while( i<=10 )
{ ;
printf(“%d “, i ); {
i++; printf(“%d “, i );
} i++;
}
this loop goes infinite, because ‘i’ is not incrementing
towards to 10. The empty loop repeats again and again
C-Family 82 Loops
Printing 1, 10, 100, 1000, 10000, 1000000 for 6 times [ do not use pow() fn ]
1. take ‘i’ as loop variable with start value 1, here ‘i’ works as loop variable as well as to print output values
2. print ‘i’ value as output
3. multiply 10 to ‘i’, to generate next output value
4. repeat step2 and step3 as far as i<=100000
5. stop.
void main()
{ int i=1;
while(i<=1000000)
, printf(“%d “, i );
i=i*10;
}
}
i=2;
while( i <= N/2 )
{ if(N%i==0)
printf(“\n not prime”);
else
printf(“\n prime”);
i++;
}
ip: N=10 (many outputs)
op: not prime // when 10%2==0 is true
prime // when 10%3==0 is false
prime // when 10%4==0 is false
not prime // when 10%5==0 is true
Here we get many outputs and it is wrong, because prime-ness can be declared only after checking with all
numbers from 2 to N/2. Here we have to take output decision only after completion of loop(not inside loop),
So, to solve this problem, better to use Boolean logic, there several other logics to find prime-ness, but this
Boolean logic is standard and best, the code is as given below
void main()
{ int n, i, bool ;
printf(“enter N value :”);
scanf(“%d”, &N);
i=2, bool=1; // assume ‘N’ is prime, so take bool as 1 (true).
while(i<=N/2)
{ if(N%i==0)
{ bool=0; // here N divided, therefore N is not prime, so set bool to 0 (false) and stop
break;
}
i++; // if N is not divided then check with next ‘i’ value until i<=n/2
}
if( bool==1) printf(“prime”); // printing output, after completion of loop
else printf(“not prime”);
}
Logic2: Count all factors of N, that is, divide N with all numbers from 1 to N and count them, if factors
count==2 then say it is “prime” or else “not prime”. This is simple logic but execution takes much time
than above bool logic, because it is unnecessary checking with all numbers if once N is divided. (here we
are not stopping by break)
count=0; i=1;
while(i<=N) // loop to count all factors between 1 to N
{ if(N%i==0)
count++; // increments ‘count’ when N is divided with ‘i’
i++;
}
if( count==2) printf(“not prime”);
else printf(“prime”);
C-Family 90 Loops
while( i<=n)
{ sum = sum + (float) p/fact;
p=p*x;
i++;
fact=fact*i;
}
printf(“sum = %f”, sum);
}
Finding sine series value: sin(x) x1/1! - x3/3! + x5/5! – x7/7! … up to 10 terms
ip: x=3, N=5
op: sum=0.1453 [ (3.0) + (-4.5) + (2.025) + (-0.4339) + (0.05424) ]
void main()
{ int i, fact, sign;
float x, sum, p;
printf(“enter sign(x) value :”);
scanf(“%f”, &x);
i=fact=1; p=x; sign=1; sum=0;
while(i<20) // adding 10 terms ( not 20, because ‘i’ is incrementing by 2)
{ sum=sum+ sign* p/fact;
sign=-1*sign; // changing ‘sign’ for next term
i
p=p*x*x; // getting next x value
i=i+2; // getting next odd number
fact=fact*(i-1)*(i); // getting next factorial value
}
printf(“\n sum =%f”, sum);
}
Printing each digit separately in a given number (N) [ printing right to left ]
ip: 2345 ip: 724
op: 5,4,3,2 op: 4, 2, 7
Logic: Extract digit by digit from right-to-left in N, and print on the screen, following steps explains it.
step1: divide N with 10 and collect the remainder(s), the remainder is always the last digit of N, when it is
divided with 10 (lastDigit=N%10)
step2: now print the last digit
step3: to get next digit of N easily, remove current last digit from N, this is by doing N=N/10
step4: repeat step-1, step-2, step-3 until N>0
Let the input is 2345, following table explains how digits are extracted.
Iteration-4 10 ) 2 (0
Here N is 2 0
----------
2 printf(“2”)
Here N is 0
( stop ) 0 (stop)
sum=0; temp=N;
while(N>0)
{ rem=N%10;
sum = sum + (rem*rem*rem); // adding sum of cubes of digit
N=N/10;
}
if(sum==temp) printf(“ Armstrong”);
else printf(“not a Armstrong”);
}
The instruction N=N/10 makes the ‘N’ to zero by the time of closing loop. There by, the original value of N is
lost after loop. So it saved in ‘temp’ before looping, later checked with ‘sum’ and result printed.
scanf(“%d”, &N);
while(N>0)
{ rem=N%10;
if(rem%2==1)
temp=rem; // if odd found then store into temp
N=N/10;
}
if(temp==0) printf(“no odd digit found”);
else printf(“\n the found odd digit is %d”, temp);
}
For example to get the first digit ‘3’ from 3456, it has to be divided by 1000, similarly to get 7 from 724,
it has to be divided by 100. According to number of digits in N, it has to be divided with 1000/100/10/1.
To generate this type of 10x value based on digit of N, the code is
p=1;
x-1
while(N/p>9) // loop to generate P value to 10
{ p=p*10; }
void main()
{ long int rem, N, sum, p;
printf(“enter any binary number :”);
scanf(“%ld”, &N);
sum=0 , p=1;
while(N>0)
{ rem=N%10;
sum=sum + rem * p;
N=N/10; p=p*2;
}
printf(“\n decimal number = %ld”, sum);
}
2 13
2 6- 1
2 3- 0
3 2 1 0
2 1- 1 10 * 1 + 10 * 1 + 10 * 0 + 10 * 1
0- 1 L R
sum=sum + rem*p;
N=N/2; p=p*10;
}
printf(“\n binary number = %d”, sum);
}
Let N=370359
16 370359
16 23147 7 0*100+7 7
16 1446 11 (B) 7*100+11 711
16 90 6 711*100+6 71106
16 5 10(A) 71106*100+10 7110610
5 7110610*100+5 07 11 06 10 05
Iteration-1 0 1 1 2 3 5 8…
X Y new=X+Y
Iteration-2 0 1 1 2 3 5 8…
X Y new=X+Y
Iteration-3 0 1 1 2 3 5 8…
X Y new=X+Y
void main()
{ int X, Y, new, i;
X=0; Y=1; i=0;
while(i++ < 10)
{ printf(“%d\t”, X);
new=X+Y; // generating next fibo number
X=Y; // advancing X to Y and Y to new
Y=new;
}
}
Finding GCD of two numbers
ip: 12 18
op: gcd = 6
step1: Let X , Y are input values
step2: Divide Y with X and collect the remainder to R (don’t care if X>Y)
step3: If remainder(R) is zero then stop and print X as GCD
step4: If R is not zero then take X as Y and R as X for next cycle and continue this process until R is zero.
int x , y , rem;
scanf(“%d%d”, &x, &y);
while(1)
x y x y stop
{ rem=y%x;
12 ) 18 ( 1 6 ) 12 ( 2
if(rem==0) break;
12 12
y=x; // take x as y
6 0 x=rem; // take rem as x
}
printf(“\n GCD = %d”, x);
C-Family 104 Loops
3,4,5 5 5 35
5,6,7 1 1 7
1 1 1
void main()
{ int x,y,z, lcm=1, i=2, bool;
printf(“enter 3 numbers :”);
scanf(“%d%d%d”, &x, &y, &z);
while( x>1 || y>1 || z>1) // repeat until all becomes 1.
{ bool=0;
if( x%i==0 )
{ bool=1; x=x/i;
}
if( y%i==0 )
{ bool=1; y=y/i;
}
if( z%i==0 )
{ bool=1; z=z/i;
}
if(bool==1) lcm=lcm*i; // then take ‘i’ as factor
else i++; // if no number divisible then try with next number(s)
}
printf(“\n lcm = %d”, lcm);
}
C-Family 105 Loops
intialization
This loop repeats as long as the condition is true, first it enters into loop-body through initialization-part.
From 2nd cycle, the control enters through increment/decrement part. This is as given below
Note: for-loop header must have only two semicolons, if not, it is an error.
Let us have some examples,
C-Family 108 for- loop
loop to print odd numbers from 1 to 100 loop to print odds from n to 1.
for(i=1; i<100; i=i+2) for(i=n; i>0; i--)
{ { if( i%2==0)
printf(“%d “, i ); printf(“%d “, i );
} }
eg) all the three parts of loop header may or may not be presented, we can avoid any part just by leaving it
blank. However, the two semicolons must be presented as they indicate separation of three parts.
do-while loop
The do-while loop is quite opposite to while-loop, in case of while-loop, the condition part appears at the
top of loop-body, whereas for do-while loop, the condition part appears at bottom of loop-body.
Thus while-loop is top-test construct, and do-while is bottom-test construct.
As a result, the do-while body executes at least once irrespective of condition is true/false.
The while-loop may or may not be executed; it may fail at the beginning, at least without executing once.
But do-while loop executes at least once irrespective of condition is true/false.
This is rarely used in the programing, who wants to execute loop body at least once.
Syntax is
do
Instruction 1
{ instruction 1; Instruction 2
instruction 2; ---
instruction N
-----
----
instruction N; true
condition
} while( condition ); // bottom test-condition
instruction N+1; false
instruction N+2;
Instruction N+1
InstructionN+2
---
Some programmers dislike do-while loop because of its structure, so they always avoid with the help of
while-loop using break statement, which is as given below
while(1)
{ ----
----
----
----
if(condition) break; // bottom test-condition, now it is like do-while loop
}
“Continue” is also a condition less control statement, skips some instruction in the loop when it gets
executed. When continue gets executed then the control immediately transfers back to beginning of loop
and follows next cycle, so that bottom instructions are bypassed. This is as shown below
while ( condition )
{ instruction 1;
instruction 2;
if( condition )
continue;
instruction 3;
instruction 4;
instruction 5; // instructions-3 to instruction-N are bypassed by continue
----
instruction N;
}
output: 1 2 3 4 output: 1 2 3 4 6 7 8 9 10
C-Family 114 Nested-Loop
while(condition )
while(condition 1) {
{ instruction 1;
instruction 1; instruction 2;
instruction 2; …..
….. instruction k;
instruction k; for( initialization; condition; increment )
{
while(condition 2) instruction k+1;
{ instruction k+1; instruction k+2;
instruction k+2; ……
…… instruction m;
instruction m; }
} instruction m+1;
instruction m+1; instruction m+2;
instruction m+2; …...
…... instruction n;
instruction n; }
}
C-Family 115 Nested-Loop
Observe the inner loop ‘j’ in each & every iteration at outer loop is
1st iteration, when i=1 for(j=1; j<=1; j++)
printf(”%d “, j ); // 1
The first ‘j’ loop prints the 12345, whereas second ‘j’ loop prints the 54321
5 blanks
for(x=5,i=1; i<=6; j++)
1
{ for(j=1; j<=x; j++) // loop to print blanks
4 blanks 2 2
printf(“⨿“); // ‘⨿’ this is space bar
3 blanks 3 3 3 for(j=1; j<=i ; j++)
2 blanks 4 4 4 4 printf(“%d⨿“ , i );
1 blanks 5 5 5 5 5 printf(“\n”);
0 blanks 6 6 6 6 6 6 x--;
…6 rows
}
The 1st inner j-loop prints the spaces before
printing numbers
the second inner loop prints the numbers.
Try without using ‘x’.
C-Family 118 Nested-Loop
11 to get this pattern, some spaces need to be added before each row,
1221 which is below shown
123321 7 blanks 1 1
12344321 6 blanks 1 2 2 1
1234554321 5 blanks 1 2 3 3 2 1
123456654321 4 blanks 1 2 3 4 4 3 2 1
12345677654321 3 blanks 1 2 3 4 5 5 4 3 2 1
1234567887654321 2 blanks 1 2 3 4 5 6 6 5 4 3 2 1
1 blacks 1 2 3 4 5 6 7 7 6 5 4 3 2 1
0 blanks 1 2 3 4 5 6 7 8 8 7 6 5 4 3 2 1
5 blanks
for(x=5,i=1; i<=6; j++)
*
{ for(j=1; j<=x; j++) // loop to print blanks
4 blanks * * *
printf(“⨿“);
3 blanks * * * * * for(j=1; j<2*i; j++)
2 blanks * * * * * * * printf(“*“);
1 blanks * * * * * * * * * printf(“\n”);
0 blanks * * * * * * * * * * * x--;
…6 rows
}
The 1st inner j-loop prints the spaces before
printing numbers
the second inner loop prints the stars.
Try without using ‘x’.
0 blanks * * * * * * * * * * *
N=6;
1 blanks * * * * * * * * * for(X=N, i=0; i<N; i++)
2 blanks * * * * * * * { for(j=0; j<i ; j++) // loop to print blanks
3 blanks * * * * * printf(“ “); // single space
4 blanks * * * for(j=0; j<2*X; j++)
5 blanks * printf(“*“);
printf(“\n”);
X=X-2;
}
C-Family 119 Nested-Loop
Space for all items of array is allocated in contiguous memory locations in the RAM and each item is
accessed with their index value. For above values, the index of 13 is 0, 26 is 1, and 7 are 2 and so on.
Arrays can be extended to any number of dimensions, but most of the time, we use single or double
dimensional arrays. Syntax to declare array is:
int X[5]; single dimensional array int Y[5][6]; two dimensional array
Y[2][0] … … … … Y[2][5]
Y[3][0] … … … … Y[3][5]
Y[4][0] … … … … Y[4][5]
Here, the ‘X’ is an array name, which holds 7 integer items. The declaration of array is same as any other
normal variable except the array-size. The size should be mentioned with constant value and which
represents count of elements that are collectively created as array.
More about array initialization: Syntax is: data-type array-name[ array-size ]={ list of initial values };
note: the list of initial values should be surrounded by pair of braces { }
int a[5]={10,20,30,40,50}; 10 20 30 40 50
eg2) int a[ ]; // error, size must be given at coding time (empty array not allowed)
If all inputs are –ve like -12, -45, -6, then the condition if( bigg<a[i] ) always fails, because initial value of bigg
is zero, here no array value is > zero, so output zero is printed as big value. So, to solve this problem,
initialize bigg & smalll with any one element in the array before loop. It is better to initialize with a[0].
C-Family 128 1D-Arrays
void main()
{ int a[20], i, j, n, temp;
printf(“enter no. of input values n :”);
scanf(“%d”, &n);
printf (“enter %d values to array :“, n);
for( i=0; i<n; i++)
scanf(“%d”, &a*i+);
for(i=0, j=n-1; i<j; i++, j--)
{ temp=a[i];
a[i] = a[j];
a[j] = temp;
}
printf(“\n after reversing, the array elements are \n”);
for(i=0; i<n; i++)
printf(“%d “, a*i+);
}
99 87 43 34 17
45 56 77 60 22
87 43 34 44 22
A[0] A[1] A[2] A[3] A[4] A[5] A[6] A[7] A[8] A[9] A[10] A[11] A[12]
Now write a program yourself, where accept N values from KB and delete kth element in the array(k<N)
later print all elements after deleting kth element.
C-Family 131 1D-Arrays
45 56 77 60 99 87 43 34 44 22
A[0] A[1] A[2] A[3] A[4] A[5] A[6] A[7] A[8] A[9] A[10] A[11] A[12]
void main()
{ int a[20],i, k, new;
printf(“enter [Link] input values n :”);
scanf(“%d”, &n);
printf(“enter %d values to array : “, n);
for( i=0; i<n; i++)
scanf(“%d”, &a*i+);
printf(“enter new element and position to insert :”);
scanf(“%d%d”, &new, &k);
for(i=n; i>=k; i--) // shifting elements to right-side
a[i] = a[i-1];
a[k-1]=new; // inserting new element
n++; // now array contains n+1 elements
printf(“\n after inserting elements, the array is :”);
for( i=0; i<n; i++)
printf(“%d “, a*i+ );
}
21 44 55 62 56 23
B[0] Bb[1] B[2] B[3] B[4] B[5]
C-Family 133 1D-Arrays
int a[10]={0};
int n;
scanf(“%d”, &n );
while( n>0 )
{ a [ n%10 ]=1 ;
n=n/10;
}
for( i=0; i<10; i++)
{ if( a[i]==1 )
printf(“%d “, i );
}
-----------------------------------------------------------------------------------------------------------------------------------------------
Functions
Function is a subprogram that performs a given sub-task in a program. It is an independent block of
code with a name to perform a specific task. Functions mainly provide reusability and modularity. It breaks
down a big program into several sub programs for easy handling. Thus, collection of functions makes a good
C-program. In computer science, the function is also called routine, subroutine, subprogram, procedure, or
method or module.
While developing a big application, it should be designed in such a way that, it is divided into
several meaningful modules and each module again divided into several sub-modules called functions.
For example, let us consider student automation project in a school, it can be divided into several modules
say admission, attendance, exam-test, fees, games, etc. Each of these modules is made up of several
functions which accomplish individual tasks. Generally, every module is developed in separate files like
“admission.c”, “attendance.c”, “exam-test.c”, etc; all these files may developed by several people and
finally integrated to build the whole project.
Types of functions
Functions are classified into two types: 1. Library functions 2. User-defined functions
Library functions: These are ready-made functions, which are designed and written by the C
manufactures to provide solutions for basic and routine tasks in the programming. For example I/O
functions printf() & scanf(), mathematical functions pow() & sqrt(), etc. The vendor of C, supply these
predefined functions in compiled format with C software. There is huge collection of functions available to
meet all requirements in the programming, thus this collections are called functions Library.
User-defined functions: We can write our own functions as per our requirement just like any library
function. There is no conceptual difference between user-defined and library functions, all works in similar
manner, besides, our functions can be added to existing library and we can use like a library function.
If more collections found, then we can create our own library.
In C, the main() is also a user defined function, the word ‘main’ reserved by the complier but its body has to
be implemented by the programmer. The main() function works as start & end point of program, and
remaining functions are executed by transferring(call) the control temporarily from main().There is no syntax
difference between main() and other functions, all works in similar way.
Let us see the following example, which illustrates how the functions are executed in the program.
void main()
{ int findBig ( int x, int y)
int k; { int z;
if( x>y)
k=findBig(23,4); z=x;
else
printf(“%d”,k); z=y;
} return(z);
}
The instruction k=findBig(4,23) is a function-call statement in main(), when it gets executed, the control
jumps to the findBig() fn body along with values (23,4), and these values are assigned to (x, y) variables, after
calculating big value(z), it returns and assign back to k, this is as shown above.
In this way functions are executed.
C-Family 135 Functions
*the passing input values to function is said to be arguments, whereas the receiving variables of such
arguments is said to be parameters. In this example, the values(23,4) are called arguments and (x, y) are
called parameters. The arguments and parameters count must be matched, and type must be compatible.
*In this program, we have two functions main() and findBig(). Here the main() is invoking(calling) the
findBig(), so in this context main() is said to be calling-function, whereas findBig() is said to be called-
function.
*Here the word “findBig” is said to be the function name and it follows the rules of variables name. We can
give any name to the function just like a variable name in the program.
*The type int before the function name is said to be return-value-type. In this example, the function is
returning ‘z’ value as int, therefore return-value-type declared as int. The return-type explicitly tells what
type of value the function is returning. It is useful for compiler to check syntax errors as well as to the
programmer for documentation.
*Thus, every function does something and returns a calculated value to the calling-function, all functions
including main() follows same syntax rules with one or two optional statements. The following figure shows
the each & every entity of function
Return-value-type
Return-value-type
Here this ‘return’ statement is not required, because, the last closing
braces ‘}’ of function works as “return” statement.
This is said to be “return-value-type” of a function, this type must be matched with the return-value
of a function. In this example ‘z’ is returning as int, therefore return-value-type declared as int.
C-Family 136 Functions
The function findTax() is taking employee salary as input(argument), and after calculating tax amount, it
returns and assigns back to ‘tax’. This is as shown in the above figure, here the variable ‘salary’ is said to be
argument, whereas ‘sal’ is said to be parameter. In the above findBig() example, the arguments (23,4) are
constants, but in this example, argument salary is a variable. Here value of salary is passed as argument to
the function. Sometimes argument and parameter names can be same, but they are different copies, let us
see following example
Here argument and parameter variable’s name are same, but they are different copies, so in this total
program two ‘salary’ variables and two ‘tax’ variables exist. One set belongs to main() fn and second set
belongs findTax() fn (A separate memory space is created for each set like above shown picture).
So, argument variables are always different from parameter variables, parameters work like a copy of
arguments. It can be imagined as parameters are place-holder of arguments. Generally, beginners get
confusion when argument & parameters names are same.
C-Family 137 Functions
* The fact() function takes argument ‘N=5’ as input and stores into parameter ‘X’.
* After calculating factorial value, it returns and assigns back to ‘k’.
* In this way, function can be called as many times as we want. Let us see in next example, how functions
can be called more than once.
void main()
{ int N=5, result; int findSum( int N)
result=findSum(N); // function call { int i , sum=0;
if( result==N*(N+1)/2 ) for(i=1; i<=N; i++)
printf(“program is correct”); sum=sum+i;
else return sum;
printf(“program has some logical errors”); }
}
void main()
{ float sum=0, v1, v2;
int i;
for(i=1; i<=N; i++)
{ v1=power(x,i);
v2=fact(i);
sum=sum+v1/v2;
}
printf(“sum is %f”, sum);
}
Syntax of function
Function has 3 syntaxes
1. Function definition/body ( defines the code of function )
2. Function calling/invoking ( executing the function task)
3. Function proto-type ( function declaration like variable declaration, discussed at end of this chapter)
① Syntax of function-body
return-value-type function-name( parameters-list )
{ variable-declaration;
instruction1;
instruction2;
……..
return(result);
}
The function body defines the task of function, ie, what it does. It defines function’s task with input &
output values. The body executes when it is called explicitly from other part of program. Every function
follows this syntax with one or two optional statements.
* Calling a function means invoking the function task, ie, asking the function to do his respective job. When
the above function-call statement gets executed, the control transfers to its body along with arguments and
after executing all instruction within the body, the control returns to same point of call-statement.
* To understand the mechanism of function-call, let us consider a simple example. Suppose owner of house
wants some groceries, so he calls his assistant and gives some money to him, later assistant brought and
returns to him. In the first example, the owner is main() and assistant is findBig(). Here main() wants to find
the big of two, so it called the findBig() and gave arguments (23,4) to him. In this way functions work.
* Function name: the function name should be relevant to function’s task, it should express the purpose of
function. For example, if a function finds square root of a value, then it is better to name it as ‘sqrt()’. The
body of function invokes by calling with this name.
* Calling vs Called: Here the main() is calling the findBig() function, so in this context, main() is said to be
calling-function whereas findBig() is said to be called-function.
* Arguments vs Parameters: Arguments are nothing but input values of function. When a function is called,
they are passed from calling-function to called-function along with the control. Whereas parameters are
variables, which receives (hold) the argument values at called-function. (Arguments are values whereas
parameters are variables)
* return statement terminates the current task of function and returns the control to calling-function
with/without a value.
* function’s-limitation: The ‘C’ function can return only one or none value using ‘return’ statement,
because the syntax provided in that way, to return more values pointers are used. (we will see later)
Note: we have a freedom to write functions in any order, that is, main() function can be written at bottom of
big() function, but as the main() fn is starting point of program, the compiler automatically moves it to
beginning in executable file. In this way programmer has a freedom to write functions in any order.
void main()
{ int k, A=2,B=3,C=4 ;
k=power(A , 10) + power(B , 5) + power(C , 2); // here power() fn called 3 times.
printf(“\n output is = %d”, k );
}
void main()
{ float pie()
float area, radius=8; {
return 3.14;
area = pie() * radius *radius; }
The above “welcome()” function is just displaying a message on the screen, it is taking no argument and
returning no-value. Therefore, the return-value-type ‘void’ has given in this example. The last closing braces
of a function works as “return” statement, therefore “return” is an optional statement at the end of
function. As we know, the main() function generally returns no-value, that is why we always write main()
function body as “void main(){…}”
C-Family 145 Functions
void x()
{ printf(“\n before y() function”);
y();
printf(“\n after y() function”);
}
void y()
{ printf(“\n On behalf of C-Family Computers”);
}
before x() function
before y() function
On behalf of C-Family Computers
after y() function
after x() function
* Scope of variables
If any variable is declared within a block then it becomes local to that block and cannot be used or accessed
outside of that block
void main()
{
{
int k;
k=100;
}
printf(“%d ”, k); // error, undefined symbol ‘k’
}
}
Here compiler shows an error message called “undefined symbol k” at printf() statement, because the
variable ‘k’ declared in inner block and we are trying to access or print outside. Thus ‘k’ cannot be used other
than that block. In this way, variables are block-scope. Let us see one more example
example2: void main()
{ int k=100;
test();
printf(“the k value =%d”, k);
}
void test()
{ k++; // error, undefined symbol ‘k’
}
Here compiler again shows same error message “undefined symbol k”. The variable ‘k’ declared in main()
function block and we are trying to access in test() function block. In this way, function block is also a block
and we can’t access one block variables in another block.
example3: void main()
{ {
int k;
k=100;
}
{ int k;
k=200;
}
}
Here two copies of ‘k’ variables exist in this program, both memory addresses are different. The first ‘k’
belongs to first inner block and second ‘K’ belongs to second inner block.
Example 1 Example 2
n n
void main() 10 void main() 10
{ int n=10; { int n=10;
printf(“\n before calling =d”,); printf(“\n before calling = %d”, n);
test(n); test(n);
printf(“\n after calling = %d “, n); printf(“\n after calling = %d “, n);
} }
if one wants to change the n through x, then pointer are Both programs show same output.
required. We will see in next chapter.
return(0) defines the normal termination of program and it closes all files, i/o streams and other resources
before termination of program.
return(1),return(2), etc defines the abnormal termination of program, here OS records the error-code or
error-type in log files for future reference. (Like history in web-browsers)
C-Family 151 Functions
1) function with arguments and return value: most of the calculation functions take arguments
and returns a value. For example, finding factorial value.
2) function with arguments and no return value: some functions take arguments but returns
nothing, eg printing multiplication table.
3) function with no arguments but returns a value: this task is less common in programming, takes
no arguments but returns a value, like calling: rand() fn, getTime() fn, getDate() fn, getGPS() fn.
4) function with no arguments and no return value: this is used for fixed jobs, the tasks like clearing
screen, printing common messages.
5) Function proto-type
This concept is very good for senior programmers when they want to create abstract data-types, but for
beginners who learning C, it seems to be worst concept. It creates much confusion over function-call vs
function-proto type. Good news is, in some modern compilers this concept is optional.
The English word proto-type means a model to an actual implementation, in C, it is used to introduce the
function to the compiler to give an idea about the return-type, function-name, argument-type and count.
Let us see, why it is required
void main()
{ ---
k=test(20,30); // function-call
---
}
float test(float a, float b) // function body
{ return(a+b);
}
In C, functions are compiled in an order in which they are written in the program. Here first main() fn, later
test() fn will be compiled. While compiling main() function, at that time, compiler doesn’t know about test()
function(because its body appeared at bottom). When compiler faces the call statement “k=test(20,30)”,
it notices and assumes, the ‘test()’ is a function with arguments 20,30. Based on this call statement,
compiler understands it as, the function is taking two int-type arguments by seeing (20,30) and returning
int-type value. (because default return type is int)
But later, when compiling test() function-body, it will notices as, it is taking ‘float-type’ arguments with
return value float, therefore, this leads to data-type mismatch error between call and body.
To solve this problem, we have two options,
1. Declare the function proto-type before first call
2. Define the function body before first call. (called-function before calling-function)
float test(float , float); // function proto-type float test(float a, float b) // this body itself works as proto-type
void main() {
{ --- return a+b;
k=test(); }
---
} void main()
float test(float a, float b) { ---
{ k=test();
return(a+b); ---
} }
proto-type declaration is nothing but, first Note: if called-function body is provided before calling-
function-header line terminated by semicolon. function, then the body itself works as proto-type.
this is as shown above. In this case, no special proto-type required
C-Family 153 Functions
7) Advantages of functions
Reduces repetition of code: the repeated code can be converted into a function and called as many
times as we want in the programing.
Code reusability: Once, if function is made ready for use, it can be used several times in several programs
where ever it is necessary. Thus, reuse of function makes the programming easier and speed. Generally,
programmers develop applications from already existing code not from zero level. As we know pow(), sqrt(),
printf(), scanf(),…etc are preexisting functions and they are using many times almost in every program.
Reduces complexity: when a big program is divided into several functions, it reduces complexity,
improves readability, easy to modify and also debugging made easy.
Ease of debugging: debugging means finding syntax and logical errors. If any error occurs in a particular
function then it doesn’t require checking in other functions. Therefore, it is easy to find errors.
Increases readability: By observing function call statements (function-name), one can understand what
the function does, functions written by several people for several purposes. Generally, one doesn’t involve
or try to know how other’s functions made it. For example, we are calling “sqrt()” without knowing how it
works. So it is easier to understand the logic when program is made up with collection of functions. By
observing only function call statements in the program one can easily understand the entire logic.
Easy to modify: if one function is modified, that does not affect the other functions as they are
independent.
Portability: in computer science, C became a vital language, its usage extended in almost all fields in the
real world. Therefore, today, the C software is available in most of the computer environments. If a function
is developed on a particular operating system then it can be easily adapted to other operating systems
without/negligible modifications. Such written functions are portable and generic.
C-Family 154 Functions
C-Family 155 pointers
Pointers
Pointers play an important role in C language; the excellent features of pointers have made ‘C’ a vital
language in computers world. In some other languages like Pascal, Basic, etc where pointers are not
programmers-friendly as they are in C. In C, pointers are simple to use and programs can be made efficiently
and compactly. They give tremendous power to the programmer. A veteran programmer feels that, in the
absence of pointers no application could be made as efficiently as he expected. However, pointers are
dangerous too, for example a pointer variable containing an invalid address can cause the program to crash.
In programing, in all situations, we cannot access the data directly using variable name. The alternative is,
accessing the data indirectly through its address; this is achieved through pointers. Pointers provide quick
and dynamic access of arrays. Actually, array values implicitly managed through this indirect access
technique only. Because, we can’t provide a name to each value in the array, where all values are accessed
through single pointer. Pointers are preferred mostly in manipulation of arrays, strings, lists, tables, files, etc.
They have well support of implementing dynamic data structures like array-lists, linked-lists, stacks, queues,
sets, trees, graphs , etc.
Definition of pointer
Pointer is a special type of variable, which is used to store address of memory location, so that, such
memory location can be accessed through pointer from any point in the program. In this way, pointers
provide indirect memory accessing.
We know that, memory is a collection of bits, in which each eight-bits constitute one byte. Every byte has its
own unique location number called address. This location number (address) is just a serial number of the
byte sequence. For example, first byte address is 1, second byte address is 2, and so forth. To store this
address, we need a special kind of variable called ‘pointer variable’.
Address of memory location is just a serial number in the byte sequence, so, to store such address, a normal
integer variable is enough. However, indirect accessing is difficult, because the compiler cannot determine
whether the variable is holding an address or value. To work with pointers, we have two unary operators
Reference/address operator (&)
De-reference/value operator (*)
The ‘&’ and ‘*’ operators work together for referencing and de-referencing.
k variable name
int k=10; value
10
2020 2021 assumed addresses
The address of a variable may not be always a fixed location like 2020 as shown in above, and it is
randomly given by the computer. Here we assumed k’s address is 2020.
C-Family 156 pointers
Here the expression ‘&k’ is pronounced as “address of k”. The space for ‘k’ at run time may allocate
anywhere in the RAM, and to get such address, the reference operator(&) is used.
The format string %u or %p is used to print the address. [%pprints the address in hexadecimal format]
We know that, the variable ‘k’ occupies two bytes in memory. Suppose, it has occupied memory
locations 2020 & 2021, only the first byte address (2020) is considered to be the address of ‘k’ by the
compiler. As compiler aware that ’k’ occupies two bytes in memory, if the first byte address is 2020 then
obviously the second byte address would be 2021. So, we always take first byte address as the address
of a variable irrespective of variable size.
Remember that, address is an unsigned-int type value.
X Y Z
10 int 20.45 float ‘A’ char
2000 int* 3000 float* 4000 char*
Address types are derived types, by adding a symbol star (*) to the any existing data-type, it becomes as
address-type. For example,
The data type “int*” derived from “int”
“int**” derived from “int*”
“int***” derived from “int**”
……… in this way we can extend pointers up to any number of times (infinite times)
Similarly, we can define all other types. Notice, pointers are infinite types.
C-Family 157 pointers
For example: int *p; // called integer pointer, it holds a integer variable address
float *q; // called float pointer, it holds a float variable address
Here p and q are pointer variables and they are capable of holding address of int & float variables
respectively. Here p is also called a pointer to int and q is called a pointer to float. The integer pointer is
used to access the integer value indirectly and a float pointer is used to access the float value indirectly.
Note: Address is an integer type value, to store such address, pointers occupy 2bytes memory.
Therefore, all type pointers occupy 2-bytes. Here p & q occupy 2bytes each. (we see later more clearly)
Let us have some demo programs to get command over pointers and their applications.
Demo 1
void main()
{ int k=10;
int *p; // here ‘*’ is used to declare ‘p’ as a pointer variable
p=&k;
printf(“\n output1 = %d”, *p); //here ‘*’ is used to access k’s memory
*p=20; // here also ‘*’ is used to access k’s memory
printf(“\n output2 = %d”, *p);
printf(“\n output3 = %d”, k);
}
Here the purpose of the instruction ‘int *p’ is to declare p as a pointer variable. So here, the purpose of
‘*’ is to specify the p as a pointer variable instead of normal variable.
The expression ‘*p’ in printf() statement accesses the k’s memory
When the p is assigned with ‘&k’, it can be called as “the pointer p is pointing to k”, this is visualized as
above figure.
C-Family 158 pointers
Demo 2
This demo program tells how two pointers can points to same location.
void main()
2020
{ int k=10, *x, *y; X 4040
x=y=&k; // both pointers x, y is assigned with &k K
printf(“\n output1 = %d %d”, *x, *y); 10
*x=20; Y 2020 2020
*y=30; 5050
k=40;
printf(“\n output2 = %d %d %d”, *x, *y, k);
}
Output1: 10 10
Output2: 40 40 40
Any number of pointers can points to one variable (one location), if the value is changed through one
pointer then the other pointers also gains changed value.
Here both pointers x,y pointing to the ‘k’. Hence k’s memory can be accessed in three ways using direct
access k, using indirect access *x, and *y; here all expressions *x, *y, k accesses same location(k).
Demo 3
This demo program swaps two values using pointers.
void main()
{ int k1=10, k2=20, *x, *y, t; X K1 (*x)
x=&k1; 2000 10
y=&k2; 4000 2000
t=*x; // t=k1; Y K2 (*y)
*x=*y; // k1=k2; 3000 20
6000 3000
*y=t; // k2=t;
printf(“\n output1 = %d %d”, *x, *y);
printf(“ \n output2= %d %d”, k1, k2);
}
Output:
output1 = 20 10
output2 = 20 10
Demo 4
Expect the output of following program.
void main() X K1 K2
{ int k1=10 , k2=20 , *x; &K1 10 20
x=&k1;
*x=30;
x=&k2; X K1 K2
*x=40; &K2 10 20
printf(“\n %d %d %d %d”, *x, k1, k2);
}
Here the pointer ‘x’ initially pointing to ‘k1’, later it is changed to ‘k2’;
so the expression “*x” accesses the memory which is currently pointing to.
C-Family 159 pointers
Demo 5
Demo program for swapping two pointers and it is just like swapping two integer values.
} X K1
Output: &k2 10
output1 = 20 10 2000 4000
output2 = 10 20
Y K2
&k1 20
3000 5000
Initially x,y are holding address of k1,k2; after swapping x & y, ‘x’ redirected to k2, ‘y’ to k1.
In this way, we can change the pointing address while running a program. Let us have one more example
Demo 6
Expect the output of following program.
void main()
{ int k1=10, k2=20;
x=&k1; y=&k2;
*x=*x+*y;
*y=*x+*y;
printf(“ \n output2= %d %d”, k1, k2);
}
Demo 7
Expect the output of following program X Y K
void main() &k &k 10
{ int k=10, *x, *y;
x=&k;
y=x;
*y=55; *x=66;
printf(“\n %d %d %d %d”, *x, *y, k);
}
Demo 8
void main()
{ int k1=10, k2=20 , *x , *y;
x=&k1; y=&k2;
printf(“\n enter any two values “);
scanf(“%d%d”, x, y); // passing x,y values to scanf(), which are nothing but &k1, &k2;
// this call can be taken as: scanf(“%d%d”, &k1, &k2);
printf(“\n %d + %d = %d”, k1, k2, *x+*y);
}
C-Family 160 pointers
Here ‘p’ and ‘q’ are pointers of type ‘int*’ and ‘float*’ types respectively.
If there is any data type like ‘XYZ’ then ‘XYZ*’ will become a pointer type.
Let us see, how main memory(RAM) managed in the computer: Memory is a large collection of bytes, in
which it is divided into several logical blocks called segments, and each segment contains 65,535 bytes (64K)
called offsets. The size of segment may vary from one to another operating system. This is as given below
Segment 1 Segment 2 Segment 3 …
For example: int k=10; // Let us say, the variable ‘k’ allocated in 2020th offset of 3rd segment, then k address
would be 3:2020, but our programs print this address as a single number like 32020.
K variable name
10 value
th rd
3: allocated in 2020 offset of 3
2020 segment
Conclusion: based on compiler and operating system, the pointer takes 2/4 byte.
the expression *p access only the first 2byte of pointing memory as int-type, like above picture(2000+2001)
the expression *q access the first 4byte of pointing memory as float-type (2000 to 2003).
As p is int* pointer, it access only the first 2byte memory as ‘int’ type.
As q is float* pointer, it access only the first 4byte memory as ‘float’ type.
in this way, pointer access pointing memory. Let us see following example,
printf(“sizeof(p) = %d”, sizeof(p)); // sizeof(p) = 2
printf(“sizeof(*p) = %d”, sizeof(*p)); // sizeof(*p) = 2
printf(“sizeof(q) = %d”, sizeof(q)); // sizeof(q) = 2
printf(“sizeof(*q) = %d”, sizeof(*q)); // sizeof(*q) = 4
printf(“\n before incrementing, the address is =%u %u”, p , q); // say output 2000, 4000
p++; q++; // p increments by 2, q increments by 4
printf(“\n after incrementing, the address is =%u %u”, p , q); // output will be 2002, 4004
While accessing array elements using pointer, the incrementing/decrementing is required, where ‘int*’
increments by 2 to access next element in the array, similarly ‘float*’ increments by 4. We will see this
incrementing concept next topics.
C-Family 162 pointers
Pointer conversion
In C programming, sometimes, we need to access one of type data from another type of pointer, where
pointer conversion is needed. Here pointer needed to be type-casted as per pointing value. The following
example explains how ‘long int’ value can be accessed through ‘int*’ pointer.
void main()
p k
{ long int k=100;
&k
int *p;
2 bytes + 2bytes
p=&k;
printf("\n output 1 = %ld", *p);
printf("\n output 2 = %ld ", *(long int*)p);
} Converting data-type ‘p’ from int* to long int*
Output:
output 1 = garbage
output 2 = 100
As we know, the expression *p access only first 2 bytes of k memory as p is int* pointer. For accessing total
value of k then p should be type-casted to long int*. This is shown in second printf() statement.
q=NULL;
---
}
int * P = &k; first box is: int *p; and second box is p = &k;
Above initialization can be considered as:
int *p;
p = &k;
C-Family 164 pointers
{ int k=10; K
10 20
printf("\n before call = %d" , k);
2020
test(&k);
printf("\n after call = %d ", k);
}
void test( int *p) // int *p=&k; test() function
{ p
2020
*p=20;
4040
}
before call = 10
after call = 20
When the test() function calls in main(), the ‘&k’ passes and assigns to parameter p,
thereby using p, we can read/write/modify the value of k from the test() function.
Here the expression *p=20 assigns 20 to k.
this calling mechanism is known as call-by-reference
C-Family 165 pointers
Arrays VS pointers
Arrays implicitly managed as pointers by the compiler, here all array expressions are converted into pointer
expressions by the compiler. For example, the expression A[i] is converted into *(A+i) and we can also
interchangeably use array expressions as pointer expression and vice-versa. Here array name works as
constant pointer variable, which holds the address of first element. This is as given below
int A[5]={10, 20, 30, 40, 50};
P
2000
8000
C-Family 166 pointers
the above pointer expression *(p+0) , *(p+1) , *(p+2)… can be written as p[0] , p[1] , p[2] , p[3]
Since *(p+i) can be written in array style as p[i]
the expressions *(p+0) p[0] *p accesses the A[0] // now p[0] and A[0] access same location
*(p+0) *(2000+0) *2000 10
Example2: if the pointer ‘p’ is set to A[2] then the expressions are as follows
int A[5] = {12,13,14,15,16};
p = &A[2]; P[-2] P[-1] P[0] P[1] P[2]
*(p-2) *(p-1) *(p) *(p+1) *(p+2)
P A[0] A[1] A[2] A[3] A[4]
2004 12 13 14 15 15
4000 2000 2002 2004 2006 2008
here p[0] is A[2] , p[1] is A[3] , p[2] is A[4] , p[-1] is A[1], p[-2] is A[0]
P After p++
2000 2002
4000 4000
C-Family 167 pointers
The first declaration ‘int *p’ makes some confusion whether the pointer ‘p’ is pointing to single-integer or
array-of-integers, so one cannot be determined immediately. Therefore, C providers gave 2 nd declaration.
But by seeing int p[], one might wrongly think, it is an empty-array, but actually it is also same as int *p.
This declaration gives a clear idea that, ‘p’ is receiving an array-address instead of single integer address.
While developing big size applications, there exist many functions and all are messed up in the program.
The called-function may not be found at bottom of calling-function, it may exist in some other file, that is
why, they recommend this array-like-pointer declaration “int p*+”. It gives clear idea that, p is pointer to an
array instead of single-value.
Let us have one more example, filling values to array at called-function.
void main()
{ int a[3];
fill(a);
printf(“\n after filling, the values are \n”);
printf(‘%d %d %d“, a*0], a[1], a[2] ); // output: 10 16 9
}
void fill( int p[] or int *p )
{ p[0]=10; p[1]=16; p[2]=9;
}
C-Family 168 pointers
Example2: following function takes array-address and number of elements, returns the sum of all values.
int findSum ( int p[] , int n )
{ int i, sum=0;
for( i=0; i<n; i++)
{ sum=sum+a[i];
}
return( sum);
}
void main()
{ int a[5], n, i, k;
printf(“enter 5 values to array: ”);
for( i=0; i<5; i++)
scanf(“%d”, &a*i+);
k = findSum( a , 5 );
printf(“\n the sum of all values = %d”, k );
}
input: enter 5 values: 4 7 8 2 3
output: sum is 24
The ability to access calling-function’s array elements at the called-function using its base-address
provides convenience for moving multiple data items back and forth between functions shows the
excellence of pointers in C.
The expression ‘*R’ accesses the ‘Q’, the ‘**R’ accesses ‘P’, the ‘***R’ accesses the ‘K’ value.
Array of pointers
In computer science, array of pointers vastly used in the programming. I recommend you to practice more
on this kind of applications. Array, which can hold the collection of addresses is known as array of pointers.
For example, we can declare array of pointers as int *p[3] instead of int *p1,*p2,*p3.
Using this concept, we handle 2D array data such as matrices and tables with flexible and compact code.
“float *p*3]. Here p[0], p[1], p[2] are pointers of type ‘float*’ each. (array of 3 float pointers)
output: 1 2 3 4 5 6 7 8 9 10
6 7 8 9 10 4000
11 12 13 14 15
11 12 13 14 15 16
6000
C-Family 170 pointers
In call by reference method, the address of arguments is passed and stored into corresponding pointer-
parameters. Now, using these parameters, we can read/write/modify the argument values.
For example, calling swap() function, incrementDate() function…etc. Let us see an example
printf(“\n before swap = %d %d”, a, b); printf(“\n before swap = %d %d”, a ,b);
swap( a , b); swap( &a, P&b); q
printf(“\n after swap= %d %d”, a, b); printf(“\n after swap= %d %d”,
&area a,b );
&circum
} }
void swap( int x , int y) // x=a, y=b void swap( int *x , int *y) // x=&a, y=&b
{ int t; x y { int t; area circum
34.56 10.45
t=x; 20 2 t=*x; x y
&a &b
x=y; *x=*y;
y=t; *y=t;
} }
Before swapping = 10 20 Before swapping = 10 20
after swapping = 10 20 after swapping = 20 10
The (a,b) values(10,20) are passed and stored in (x,y) so The swap function pointers(x, y) are pointing to main
if any changes made in (x, y) that does not affects the function’s (a, b). So the expressions (*x, *y) indirectly
values of (a, b) swaps the values of (a, b) .
As we know, using ‘return’ statement, we can return only one value from a function, because most of the
time, we return only single value, therefore the syntax was provided in that way. So, to return more values,
pointers are used. Here we can return indirectly through pointers. The above swap() function indirectly
returned the swapped values to main() function through pointers.
Let us see one example
Following function takes radius as argument and returns area & perimeter of a circle.
void find( float radius, float *p, float *q)
{ *p= 3.14 * radius *radius; // assigning indirectly to ‘area’ in main() fn.
*q=2*3.14*radius; // assigning indirectly to ‘circum’ in main() fn.
}
void main()
{ float radius, area, circum;
scanf(“%f”, &radius);
find( radius, &area, &circum);
printf(“ area = %f”, area);
printf(“\ncircumference = %f”, circum);
}
Here find() function is taking radius as input argument and calculating area & circum. These two calculated
values indirectly assigning to main() function variables area & circum through p&q pointers.
C-Family 171 pointers
3. The type difference between one to another pointer helps to determine the data type of target location
which the pointer pointing to
int* pointer points to int memory
float* pointer points to float memory
Similarly, all pointers occupy in that way.
4. Incrementing/decrementing changes the pointer from one to next location in the array
int* pointer increments by 2
float* pointer increments by 4
Pointer to function
Pointer not only points to a data, but also can points to a code. That is, a pointer can be made to points to a
function. So that using pointer, we can make function calls also. In C, every function is loaded in separate
memory location as it appears in C program. This location address is the entry point of a function, ie, it is the
first instruction address of a function. Using this address, we can shift the control from caller-function to the
called-function.
This approach seems to be unnecessary in general programming. Because in C, all functions are global, any
function can be called from anywhere in the program. However, it is possible to pass addresses of different
functions in different times to a function thereby making function-calls more flexible and abstract.
C-Family 173 pointers
To get the address of a function, use the function name without parenthesis and arguments that gives
starting address of a function. The following program gives a demo.
void main()
{ void (*p)(); // pointer to function, which takes no arguments and returns no value.
p=test; // assigning test() function address to ‘p’
p(); // calling test() function through ‘p’
(*p)(); // this is another style of calling the test() fn, this is old style.
}
void test()
{ printf(“\n Hello World”);
}
Bubble sort
In bubble sort, the adjacent pair of elements are compared one with next element, and placed into sorted
order by swapping disorder elements. ie, if a[i]>a[i+1] then swapping takes place. In this way bubble sort
works. While comparing elements, each adjacent pair imagined as one bubble, therefore it was called as
bubble sort. The process will be as follows
Step1: In first phase of loop, it compares a[i] with a[i+1], if any a[i]>a[i+1] then swapping takes place. In this
way it compares and swaps from first element to last element. After this process, the biggest element will be
moved to last position and it is said to be sorted.
Step2: In second phase of loop, it takes only first N-1 elements of array and repeats as said in step1,
(here do not take last element, because it was already sorted in previous step1). In this step, the second big
will be moved to N-1th position and it is said to be sorted. In this way, bubble sort works.
Suppose, the values are 90 10 70 30 20 and in every cycle of loop is as follows
phase1: Before 1st iteration 90 10 70 30 20
nd
Before 2 iteration 10 90 70 30 20
rd
Before 3 iteration 10 70 90 30 20
th
Before 4 iteration 10 70 30 90 20
th
after 4 iteration 10 70 30 20 90 (90 sorted here)
Selection sort
In selection sort, first it finds the smallest element in the array, and exchanges it with the first position
element. Next it finds the second smallest element and exchanges it with the second position element.
In this way selection sort works. Let us take 5 elements: 90, 30, 70, 10, 20
After every pass of outer loop, the elements is as follows
st
Before 1 iteration 90 30 70 10 20
nd
Before 2 iteration 10 30 70 90 20
rd
Before 3 iteration 10 20 70 90 30
th
Before 4 iteration 10 20 30 90 70
Consider all the time the condition a[Pllmmsos]>a[j] may not be true ,then if we take average
assignments then it is n2/4.
swapping elements in every outer-loop takes ‘n’ operations.
But swapping takes three operations, so it takes 3*n.
Now total no. of operations = total comparisons + total assignments + total swapping
= n2/2 + n2/4 + 3 * n this is proportional to n2
Insertion sort
Insertion sort inserts elements in proper places among those already in sorted order (those are sorted by
previous iterations of loop). It shifts all previous bigger elements to right hand side, so that we get a gap to
insert new element in its proper position.
How insertion sort works?
Let us take first ‘k-1’ elements in the array (sub array) and assume these are already in sorted order (sorted
by previous iterations of loop). Now take kth element, compare it with previous position elements and shift
all previous bigger elements to right hand side so that we get a gap, where insert kth element. These inserted
positions may not be a final position, as they have to be moved again to make a room for further smaller
elements, which may be encountered later.
Let us observe following elements:
10 12 16 18 19 34 14 30 35 38 55 58 40 60
For easy understating, let us take two elements 14 & 40 have to be sorted. Now take 14 and compare with
previous elements one by one and move all bigger elements (34, 19, 19, 18, 16) to right side, so that we get
a gap at 16 element place, where insert 14. In this way, insertion sort works. But this process starts from
2nd element.
C-Family 179 Sortings
In Other Cases: When the records are large size in file, then amount of time to move the data one place to
another place takes a lot of time, in this case selection sort is better than insertion sort, because selection
sort takes only N swaps.
Suppose in case of keys are strings then comparison of strings takes a lot of time than moving data one place
to another place. In selection sort no. of comparison greater than insertion sort, so in this case, insertion
sort is the best even though records are large size. (best reference book: algorithms by Robert Sedgwick)
C-Family 180 Sortings
Searching techniques
Searching is the process of finding required key element in the group of elements.
We haves several techniques in computer science, the two basic techniques are
1. Sequential or linear search
2. Binary or two-way search
void main()
{ int a[200], n, i;
printf(“enter number of input values to array :”);
scanf(“%d”, &n);
printf(“enter %d values to array:”,n);
for( i=0; i<n; i++)
scanf(“%d”, &a*i+);
printf(“\n enter element to search :”);
scanf(“%d”, &key);
k=linearSearch(a, n, key);
if(k ==-1) printf(“\n not found”);
else printf(“\n element found at %d position”, k+1);
}
Binary search
The linear search is used when input file is small or elements are not in sorted order, it takes 0(n) time.
If elements are in sorted order, the binary search is the best choice, it takes <log2(n) time.
Step1: In binary search, the array is divided into three parts at middle position, the left sub-array, middle
element, right sub-array.
Step2: If middle-element==searchKey, it returns index of middle-element and stops the process.
Step3: If middle-element < key, it continues search in left-sub-array as said in step-1.
Step4: If middle-element > key, it continues search in right-sub-array as said in step-1.
step5: Repeat step1 to step4 until left/right sub-array partition becomes<1 element or element found.
Following picture demonstrates searching for 43.
C-Family 181 Sortings
key
43
Low high
12 16 28 33 38 43 48 50 57 79
A[0] A[1] A[2] A[3] A[4] A[5] A[6] A[7] A[8] A[9]
key
43
Low high
43 48 50 57 79
A[5] A[6] A[7] A[8] A[9]
key
43
Low high
43 48
A[5] A[6]
* Here the variable ‘Y’ has declared inside main() fn block, so it cannot be accessed in show() fn block, as it is
local to main() fn block. In this way one function’s local variables can’t be accessed in another function.
* Here the variable ‘X’ has declared at the beginning of program (outside all functions), now its scope is said
to be global and it can be accessed anywhere in the program (in all functions). So, ‘X’ can be shared in all
functions in the program.
Thus Scope is the region, where the variable is available and accessible. In C, scope is of three types:
local-scope, global-scope and file-scope. The entire program’s area is said to be global scope, whereas a
smaller region surrounded by a pair of braces {} is known as local scope. (file scope discussed later)
Local scope is the scope, surrounded by pair of braces{}, in C program, we can declare local variables
anywhere in the program, but they must be declared in first line of block-open as shown in above examples.
This block may belong to if-else, while-loop, for-loop, or function-block. This variable’s scope belongs to that
block and cannot be accessed outside. These are often called local/private variables.
Global scope is said to be entire program’s area. If any variable declared at the beginning of program
(outside all functions), then it is said to be global/public variable. Let see one more example,
int X=100; // X is called global variable (now X is in global-scope)
void main()
{ int Y=200; // Y is local variable, and belongs this main() fn block
if( X < Y )
{ int Z; // Z is local variable, and belongs to this if-block only
Z=300;
}
X=200;
show( 1000 );
}
void show( int A ) // A is local variable, belongs to this fn block, and also works as parameter
{ int B=100; // B is also local variable, and belongs to this show() fn block
printf( “%d %d %d %d”, X, Y, Z, A, B ) ; //error, here Y, Z are unknown to this fn block
}
Overriding of variables
If any two variables are declared in inner and outer block with the same name, then two copies will be
created in the program, here the outer-block variable will be overridden by the inner-block variable when
the control presents in the inner-block. That is, when the control is in inner-block, then the preference is
given to inner-block variable.
void main()
{ int k=10;
{ int k=20;
{ int k=30;
printf(“ k = %d “, k); // output: k=30
}
printf(“ k = %d “, k); // output: k=20
}
printf(“ k = %d “, k); // output: k=10
}
C-Family 184 storage classes
Storage classes
We have 4 storage classes [Link], [Link], [Link], [Link]
auto & register are temporary variables, whereas static & global are permanent variables.
A variable that defined in the program possesses some characteristics such as data type and storage class.
Data type tells the memory size and value type, whereas storage class tells the behavior of a variable, such
as default initial value, scope, life-span and storage-place.
* Scope means region in which the variable is available and accessible. We have already discussed before.
* The default initial value is zero/garbage, temporary variables default value is garbage whereas permanent
variables default value is zero.
* The life span specifies when the variable comes into existence and when it goes off, that is, when the
variable’s space gets created in the RAM(life starts) & when such space gets deleted from Ram(life ends).
auto int x , y , z; // here the storage class of x, y, z is auto
static int p , q; // here the storage class of p, q is static
auto (automatic)
It is the default storage class for all local variables inside a block, that is, if any variable declared inside a
block, then by default it is auto storage class. So, the keyword ‘auto’ is optional for auto variables. Of course,
from the beginning of this book, we have been using ‘auto’ variables only.
example: auto int x, y, z; // this is equal to int x, y, z;
auto float p, q; // this is equal to float p, q;
initial value: garbage is the default initial value. (if not initialized with any value)
scope: this variable can be accessed only within the block in which it is declared (already discussed above)
life: life is within a block as long as the control presence in that block. ie, when the control enters into a
block, all of its auto variable’s space is created (life starts) and when the control leaves the block, all such
variable’s space gets destroyed (life ends).
void main()
{ test(); // calling 3 times
test();
test();
}
void test()
{ auto int k=10; // memory space of k is created here, when the control comes here
printf(“ %d “, k);
k++; // no use of incrementing before dying ( just for demo this is given )
} // memory space of k will be destroyed here, before returning to main() function
output: 10 10 10
The variable ‘k’ will be created & destroyed 3 times upon calling test() function for 3 times.
When the control enters into the test() function’s body, the ‘k’ will be created & initialized with 10 and when
the control leaves the function, the ‘k’ will be destroyed. Hence the output is 10 10 10.
Of course, it is meaningless to survive the ‘k’ in the memory after finishing the function task. Therefore, all
auto variables will be destroyed before closing the function. But rarely some variables are needed to be
survived, where the ‘static’ storage class is the choice.
C-Family 185 storage classes
static
This is also a local variable like auto, but space creates just before start of program (before main() fn starts)
and survived till the end of program, used to access/share previous function call values for next subsequent
calls. Unlike auto, the static is used to preserve the variable values even after closing the function. It will not
be recreated & reinitialized in every call of function. Only once the variable is created and exists till the end
of program. Scope belongs to local as auto, but initial value is zero.
void test()
void main() { static int k=10;
{ test(); printf(“ %d “, k);
test(); k++;
test(); }
} output: 10 11 12
The instruction static int k=10 executes only once just before main() fn starts (this instruction shifts to
before main() fn in machine code file), whereas printf(“ %d “, k); k++; executes 3 times for 3 function calls.
Example2
void main()
{ for(i=0; i<5; i++)
{ auto int X=10;
static int Y=10;
printf(“\n %d %d”, X , Y ); output: 10 10
X++; Y++; 10 11
} 10 12 … 5 times
}
The ‘X’ creates and destroys 5 times and every time it initializes with 10, so output is 10 10 10 10 10.
Whereas ‘Y’ creates only once and initializes only once with 10, so output is 10 11 12 13 14.
register
Registers are small memory units available in the processor (ALU) itself, these are inbuilt memory units in the
processor’s ALU. Before doing any arithmetic operation, the input values are moved from RAM to registers
and then given operation takes place. So, arithmetic operations are performed with the help of registers.
We know, only 4 or 5 registers are available in the processor and always 1 or 2 are busy. So other unused
registers can be used for our variables, so that, they can have faster access. It saves the time to transfer
variable values between RAM & registers. This is very much suitable for frequently used variables like loop
variables. Only local integral types (char, int, long) are allowed as registers. The floating point types, arrays,
pointers and static/global types are not allowed. Anyway, the keyword register is not a command, is just a
request to the compiler, because, if registers are not available then space allocates in the RAM.
The other behavior like scope, life, and default-initial value is same as auto type.
Example: register int a, b, c, d, e;
register float x, y, z; // error, float are not allowed
In the above declaration, all (a, b, c, d, e) may not be allocated in the registers, because, we have limited
number of registers. The x, y, z cannot be taken as register as they are float type. See following picture, here
the register names are: AX, BX, CX, DX, SX, etc
C-Family 186 storage classes
Registers in Circuits of
RAM Processor Processor ALU
Byte1 Byte2 Byte3 …. AX register Addition circuit
BX register Subtraction circuit
CX register Multiplication circuit
DX register ……
global
Already we have discussed about these variable while discussing in global scope. Let us see more detailed.
As we know, one function’s local variable can’t be accessed in another function, but sometimes, some
variables need to be accessed throughout the program (in several functions) then we declare in global
scope(outside of all blocks). Global scope is the region that doesn’t belongs to any specific function or block,
it belongs to entire program. Global variables preferably declared at the beginning of program or in a
separate file. These variables life span is till the end program (same as static). The word global is not a
keyword and hence it is not required while declaration of variable.
int k; //now the ‘k’ is global and default value is zero
void main()
{ printf(“ k = %d”, k);
test();
printf(“, k = %d”, k);
}
void test()
{ k++;
}
Output: k=0, k=1, the variable ‘k’ is now global and can be accessed (shared) in both functions.
The static & global variable’s life-scan & initial-values are same but scope is different.
The auto & register variable’s scope and initial-value are same, but storage place may not be same.
By default, stack variables contain garbage values, whereas heap variables contain zeros. For example:
auto int x; // ‘x’ contain garbage value
static int y; // ‘y’ contain zero value
C-Family 187 storage classes
extern (proto-type)
If program is very big, obviously its code may distribute into several files and each file may contain several
functions. Here, each file can be compiled independently and produced object file, later all such produced
object files can be linked together. In this compilation process, we get some problems. If one file uses global
variable but it is declared in another file then we get undefined-symbol errors. To avoid this type of errors,
we need to specify the proto-type of global variable using keyword extern.
After compiling the 1st and 2nd program files separately, the object code for those files will be created with
the file names “[Link]” and “[Link]”. Suppose, if we are using Turbo C, then the command line usage of
the compiler will be as follows
tcc –IC:\tc\include –c dis.c
tcc –IC:\tc\include –c main.c
Here “–I” specifies the include path of library functions, and “-c” is for only compilation.
Suppose if we are using C on UNIX system, then the method for using the compiler ‘cc’ is
cc –c dis.c //-c is for only compilation and not creating machine code file
cc –c main.c
the above two commands will create the object files “[Link]” and “[Link]” respectively. (in Unix it is dis.o
and main.o) Now link these object files using the linker command. (Generally, the compiler itself can handle
the linking job). The command line usage of the TCC will be as shown in the below example:
TCC –Lc:\tc\lib [Link] [Link]
here –L specifies the library files path. To do the same with UNIX’s CC
CC main.o dis.o [Link]
The above command will create the executable binary file with name “[Link]”
This extern keyword can also be used with function proto-types. This is especially when we want to access a
function that is defined in other files or external pre-compiled modules. For example
Program file1: “dis.c” Program file2: “main.c”
void display() extern void display(); // declaration of function
{
void main()
printf(“ experience =%d”, num);
{ display();
}
}
C-Family 188 storage classes
File scope
These variables are declared using static keyword in global scope, usually, file scope variables are declared
at the beginning of file, so that, they can be accessed all functions within that file. File scope variables are
local to one file and they cannot be accessed outside of file.
Program file1: “dis.c” Program file2: “main.c”
extern void display();
extern int exp; // not declaration , it is a proto-type
static int exp=14; //global to this file only
void display()
void main()
{ printf(“ experience =%d”, exp);
{ display();
}
}
If we compile these two files separately, we don’t get any error, but at linking time, we get an error called
“undefined symbol exp” in display() function. Because the variable “exp” is local to “main.c” file, since it is
declared as static, therefore it is not accessible other than this file.
C-Family 189 pre-processor directives
Preprocessor Directives
Before knowing about preprocessor directive, let us have one example, following program calculates the
area & perimeter of circle.
void main()
{ float area, perimeter, radius;
-----------
area = 3.14 * radius * radius;
perimeter = 2 * 3.14 * radius;
-----------
}
For example, if we wrote a big application, where we used pie value 3.14 in many times, say more than 50
times, after some days, if this value needs to be changed 3.14 to 3.145 then it takes lot of effort to change in
all places. If we missed in one or two places then it gives wrong output.
In such situations we think for a solution, it would be good, if it modified in one place, will affect to the total
program. For that, preprocessor directive is the alternative, here we use #define statement like given below
#define PIE 3.14 // do not give semicolon at end
void main()
{ float area, perimeter, radius;
-------------
area = PIE *radius*radius;
perimeter = 2*PIE*radius;
-------------
}
At compile time, the symbol ‘PIE’ replaces by 3.14 in every usage in the program, this replacement effects in
executable file not in our source code file. If any changes needed in future then we simply modify the code
at macro and recompile it, the compiler will generate a new ‘exe’ file by replacing old ‘exe’ file. This new exe
file updated to new value. In this way, we automate repeated constants using #define directive.
It is mandatory to symbolize the repeating constants, so that they can be easily remember and modify later
time. In this way wherever the pie value 3.14 is required, we can use PIE symbol.
------------------------------------------------------------------------------------------------------------------------------------------------
What is the preprocessor? The preprocessor, as its name implies, is a program, which
performs some kind of text manipulations just before compilation begins. It provides some facilities like
automating repeated constants, simplifies complex math equations, providing conditional compilation,
combining two or more files…etc. Actually, this is not an inbuilt feature of c-compiler, this is an additional
tool kit which helps the programmer.
Note: All preprocessor directives start with #(hash) symbol, and we can use these statements anywhere in
the program. The directives are #define , #include , #if , #else , #endif , #elif , #ifdef , #ifndef , #undef , etc
Remember, the pre-processor directive generates a new temporary file and this file is given to the compiler
as given below picture. It do not modify our source file, it creates new temporary file where it replaces PIE
with 3.14. Thus compiler does not know about #define, #include statements.
C-Family 190 pre-processor directives
Note: It is good programming practice giving macro-names in full capital letters, so that, one can easily
identify the macros in the programming. Actually, in software industry everybody follows this convention.
I strongly recommend you to follow this rule for convenience.
No need of specifying data types for the parameters, hence, we can use same macro with different data
items. For example, the above macro sum(x, y) works with all data types like sum(4.5, 5.4) of float type.
#include directive
Generally, we break down a big application into several functions and we write in several files, later these
files are combined using #include directive. This directive combines two or more files into a single file.
It is used to join the contents of one file into another file, we have 3 syntaxes
syntax1: #include “file name”
syntax2: #include ”path + filename”
syntax3: #include <file name>
The first syntax is used, when the include file is in current working directory.
The second syntax is used, when the include file is in some other directory.
The third one, when the include file is in C-software directory.
For example:
C-Family 192 pre-processor directives
here the file “main.c” contained main-program, “sub.c” file contained sub-program and the sub-file should
be included as
These two files will be clubbed into single and then given to the compiler (as shown above). In this way, we
can attach as many files as we want in the program. The sub file (included file) can have many functions but
required (called) functions only be attached to the executable file. In this manner, the C-header files
contained proto type of all functions and we must include these files for avoiding errors.
Conditional Compilation
It is possible to compile selected portions of your program’s source code. This process is called conditional
compilation and it is used widely by commercial software houses that provide and maintain many
customized versions of one program.
As we know, these days, all commercial software designed keeping in mind all the aspects of related
organizations in nature. For example, one bank’s software can be utilized in another bank with a few
modifications. We cannot determine and finalize all the details of an application at the time of program
development, for example, regarding of OS, hardware, services,…etc. Therefore, while developing software,
the programmer must predict all possibilities that occurs later stages, thereby, it is needed to write the code
for all possibilities so that we can add, remove, or modify the code according to the organizations required
by the customer(client) before installation of software. In this way, the generic program can be changed
according before delivering software with help of preprocessor. Let us see one example
#define COUNTRY 1 // 1-India, 2-US, 3-France, 4-England,…
#if COUNTRY==1
char curr*+=”Rupees”;
#elif CUNTRY==2
char curr*+=”Dollor”;
#else
char curr*+=”No currency defined”;
#endif
void main()
{ printf(“our currency = %s”, curr);
}
By changing country code in first line, the corresponding currency name is applied to the ‘curr[]’
C-Family 193 pre-processor directives
example1 example2
#define SIZE 100
#ifndef SIZE
#ifndef SIZE #define SIZE 200
#define SIZE 200 #endif
#endif
void main()
void main() {
{ printf(“\n the size = %d”, SIZE);
printf(“\n the size = %d”, SIZE); }
}
Output: the size = 100 Output: the size = 200
In the above program, unfortunately the “factorial.c” file is included two times. At compile time, the
preprocessor includes two copies of “factorial.c” file code in the program. As a result, we get an error at
compile time. To avoid this type of errors, it is better to attach the macro check condition. This is as …
Sub file “factorial.c”
#ifndef FACT
#define FACT 1
long int fact( int n)
{
long int f=1;
while( n>1)
f=f*n--;
return(f);
}
#endif
In the above code, at 1st time of inclusion of file, the symbol FACT is not yet defined, therefore the file
“factorial.c” includes to the “main.c” file, and same time the FACT defines to 1.
In 2nd time inclusion, the FACT has already been defined; therefore it will be skipped by the #ifndef directive.
C-Family 194 pre-processor directives
#undef
This directive removes a previously defined definition of the macro-name, for example
void main()
{ after void main()
#define X 20 preprocessing {
printf(“%d “, X); printf(“%d “, 20);
#undef X printf(“%d “, X);
}
printf(“%d “, X);
} Error :undefined symbol “X”
#error
Suppose programmer wants to show an error message if specific macro was not defined previously in the
program. In those cases, we may use this #error to produce an error and to stop the compilation. This #error
stops the compilation based on given condition. For example
#ifdef PIE
#define Area(r) (PIE*r*r)
#define Perimeter(r) ( 2*PIE*r)
#else
#error “the symbol PIE not defined”
#endif
If we compile the above program, we get an error message, because the symbol “PIE” has not been defined
in the program.
C-Family 195 2D-Arrays
2D arrays: int x[3][5]; Here the value 3 represents row-size, 5 represents column-size.
Then the 2D array is as follows
Columns
R x[0][0] x[0][1] x[0][2] x[0][3] x[0][4]
o
w x[1][0] x[1][1] x[1][2] x[1][3] x[1][4]
s
x[2][0] x[2][1] x[2][2] x[2][3] x[2][4]
In the last two declarations, the row size automatically calculates by the compiler. Here, the row-size equal
to (number-of-elements)/(column-size). The column size is mandatory while declaration of array.
inta[2][]={ {1,2,3}, {4,5,6} } // error, the column size must be required
void main()
{ int a[2][3]={ {1,2,3}, {4,5,6}, {7,8,9} };
int b[2][3]={ {9,8,7}, {6,5,4}, {3,2,1} };
int i, j;
for( i=0; i<3; i++)
1 2 3 9 8 7
{ for( j=0; j<3; j++)
4 5 6 6 5 4
c[i][j]=a[i][j]+b[i][j]; 7 8 9 3 2 1
} A[ ][ ] B[ ][ ]
// displaying result of the matrix
for( i=0; i<3; i++) output matrix c[][] is:
{ for( j=0; j<3; j++) 10 10 10
printf(“ %d “, c*i+*j+); 10 10 10
10 10 10
printf(“\n”);
}
}
Finding biggest of each row & column of 2D array data (R X C size matrix)
Input: Output:
23 55 66 7 row1 big = 66
31 12 61 17 row2 big = 61
5 14 98 47 row3 big = 98
2 24 8 97 row4 big = 97
void main()
{ int a[10][20], r, c, i, j;
printf(“enter row and column size of input matrix :”);
scanf(“%d%d”, &r, &c);
for(i=0; i<r; i++)
{ for(j=0; j<c; j++)
{ printf(“ enter element of *%d+*%d+ :”, i, j);
scanf(“%d”, &a*i+*j+);
}
}
C-Family 198 2D-Arrays
#define M 3 ip:
1 2 3 4
#define N 4
5 6 7 8
void main() 9 10 11 12
{ int A[M][N] = { {1, 2, 3, 4},
{5, 6, 7, 8}, op: 1 5 9
2 6 10
{9, 10, 11, 12},
3 7 11
}; 4 8 12
int B[M][N], i, j;
// transposing elements from A[][] to B[][]
for(i=0; i<M; i++)
for(j=0; j<N; j++)
B[i][j] = A[j][i];
printf("Result matrix is \n");
for(i = 0; i < N; i++)
{ for(j=0; j< M; j++)
printf("%d ", B[i][j] );
printf("\n");
}
}
void main()
{ int a[10][10], b[10][10], c[10][10];
int r1, r2, c1, c2, i, j, sum;
printf(“\n enter size of input matrix :”);
scanf(“%d%d”, &r1, &c1);
printf(“\n enter size of second matrix :”);
scanf(“%d%d”, &r2, &c2);
if( c1 != r2)
{ printf(“sizes not equal, cannot be multiplied”);
exit(0);
}
printf(“\n enter elements of first matrix :”);
st
for(i=0; i<r1; i++) // loop to multiply 1 matrix of each row
nd
{ for(j=0; j<c2; j++) // loop to multiply 2 matrix of each column
{ sum=0;
for(k=0;k<c1;k++) // loop to multiply to get element of output matrix
sum = sum + a[i][k] * b[k][j];
c[i][j]=sum;
}
}
printf(“\n output matrix is \n:”);
for(i=0; i<r1; i++)
{ for(j=0;j<c2;j++)
printf(“ %d ”,c*i+*j+ );
printf(“\n”);
}
}
Observe the multiplication stages carefully, it contained 3 loops, 1st loop is for maintaining the row index of
1st matrix, and 2nd loop is for column index of 2nd matrix. The 3rd loop is to keep the track of sum of products
of row wise of 1st matrix with the columns wise of 2nd matrix. Finally this sum is assigned to the target
matrix of relevant position.
void main()
{ int a[100][4]; // let the maximum number of student are 100, and subjects are 4.
int i, j, total[100], avg[100], n;
char result[100][20];
printf(“enter number of students :”);
scanf(“%d”, &n);
for(i=0; i<n; i++)
{ printf(“enter student %d marks of sub1, sub2, sub3, sub4 :”);
scanf(“%d%d%d%d”, &a*i+*0+, &a[i][1], &a[i][2], &a[i][3]);
}
for(i=0; i<n; i++) // calculating total, avg and the result.
{ for(j=0; j<4; j++)
total[i]=a[i][j]+a[i][j]+a[i][j]+a[i][j]);
avg[i]=total[i]/4;
if( a[i][0]<40 || a[i][1]<40 || a[i][2]<40 || a[i][3]<40 )
strcpy( result*i+, “Failed”);
else if ( avg[i] >= 80 )
strcpy( result*i+, “A-Grade”);
else if ( avg[i] >= 60 )
strcpy( result*i+, “B-Grade”);
else
strcpy( result*i+, “C-Grade”);
}
// printing result
printf(“ student idno marks1 marks2 marks3 marks4 total avg result “);
printf(“\n===================================================”);
for(i=0; i<n; i++)
printf(“\n %d %d %d %d %d %d %s“, a*i+*0+,a*i+*1+,a*i+*2+,a*i+*3+ );
}
C-Family 201 2D-Arrays
X[0][0] X[0][1] X[0][2] X[0][3] X[0][4] X[1][0] X[1][1] X[1][2] X[1][3] X[1][4] X[2][0] X[2][1] X[2][2] X[2][3] X[2][4]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
2000 2002 2004 2006 2008 2010 2012 2014 2016 2018 2020 2022 2024 2026 2028
In one dimensional arrays, the expression x[i] can be written in pointer form as *(x+i)
lly, In two dimensional arrays, the x[i][j] can be written in pointer form as *(x[i]+j) or *(*(x+i)+j)
But implicitly the expression x[i][j] is converted as *(x+i*column-size+j). This equation is called row-major
order formula. This method used by compiler implicitly to access elements in the 2D-array, because, the row
elements are expanded in column-wise. (Some other languages use column-major order formula)
Let us see how elements are accessed in 2D array
x[i][j] *(x+i*column-size+j).
x[0][0] *(x+0*5+0) *(2000+0) *2000 1
x[0][1] *(x+0*5+1) *(2000+1) *2002 2 // integer address increments by 2
x[1][0] *(x+1*5+0) *(2000+5) *20010 6
x[1][1] *(x+1*5+1) *(2000+6) *2012 7
x[2][0] *(x+2*5+0) *(2000+10) *2020 11
x[2][1] *(x+2*5+1) *(2000+11) *2022 12
Here special types of pointers are used to access the 2D array elements. For example
int (*p)[3]; pointer to 2d-array where the column size is 3. The row size can be anything.
int (*p)[3][4]; pointer to 3d-array where the row-column sizes are 3-4, table size can be anything.
void main()
{ int a[2][3]={{1,2,3}, {4,5,6},{7,8,9} };
int (*p)[3]; // pointer ‘p’ to 2d-array with the columns size 3.
p=a; // p=&a[0][0]; making pointer to 2D array
for(i=0; i<2; i++)
{ for(j=0; j<3; j++)
printf(“%d”, p*i+*j+); // p[i][j] expands to *(p+i*3+j)
printf(“\n”);”
}
}
Passing 2D array to function
it is just like passing 1D array to function, here array base address is passed and accessed through pointer.
void main()
{ int a[3][4]={ {1,2,3,4}, {5,6,7,8}, {9,10,11,12} };
display(a); // display( &a[0][0]);
}
void display( int (*p)[4] or int p[][4] )
{ int i, j ;
for(i=0; i<3; i++)
{ for(j=0; j<4; j++)
printf(“%d ”, p*i+*j+ ); // p[i][j] *(p+i*4+j)
printf(“\n”);”
}
}
The second declaration for the parameter p[][4] is also a valid and this type of declaration is allowed only for
the parameters while receiving 2D array. This is also implicitly a pointer of type “int (*p)*4+”.
Character Handling
In programming, it is often need to handle single character data items such as employee sex(M|F), marks
grade of a student(A|B|C), pass or fail (P|F), etc. These characters may be an alphabet, digit, or any other
symbol, which is to be handled as a single character item in the program.
In computer’s memory, the characters are stored in terms of their ASCII values but not in its picture form as
visible on the screen. For example, the ASCII value of ‘A’ is 65, ‘B’ is 66. Remember that, these ASCII values
are stored in its binary form as computer understands it. ASCII values are standard serial numbers given to
each alphabet, digit, and all symbols in the keyboard. This standard is called American Standard Code for
Information Interchange proposed by international computer association. Here the word “information
interchange” means, interchanging the data from one device to another device or one computer to another
in terms of ASCII values.
Hence every character internally represented in binary format and when it is to be displayed on the screen,
it converts into symbolic picture form (picture in pixel form). Internally, special software continuously
performs this graphical conversion job while displaying contents on the monitor. The hardware
manufacturers provide this kind of software. The following table shows ASCII codes of some characters set
Characters ASCII values
A to Z 65 to 90
a to z 97 to 122
0 to 9 48 to 57
‘ ‘ (blank space) 32
‘\n’ ( enter key) 13
Character constant: If any single character enclosed within a pair of single quotes is known as char
constant. Unlike integer or float constants, the char constants must be enclosed within a pair of single
quotes.(not double quotes) . Remember, the char constant value is nothing but ASCII value. For example
* 19 , 34 , 10, -10 , 567 are valid integer constants.
* 19.78 , 10.00, -10.94, -45.98 are valid float/double constants.
* ‘A’, ‘B’, ‘a’ , ‘9’, ‘+’ …etc are valid character constants.
* ‘abc’, ‘123’, ‘+12’, “A”, “5” … are not valid character constants.
Character variable: The characters ASCII values lie in between 1 to 255, so to store such values,
the C-developer Mr. Dennis Ritchie has given a suitable data type called ‘char’. The data type ‘char’ takes
1byte memory, where we can store values of range 0 to 255.
char variable1, variable2,…variableN; // this is the syntax to declare char variable
char gender , marksGrade, accountType; // here gender , marksGrade are char type variables
getchar()
scanf()
our progoram’s keyboard
Keyboard
IO buffer IO buffer
getch()
getche()
the getch() can accept any key code directly from keyboard buffer like above shown picture. It does not
show input values on the screen. Even it doesn’t wait for enter-key for input confirmation. That is, all other
io functions waits until enter-key pressed by the user. When user presses the enter-key, then io functions
starts scanning input. But getch(), getche() does not wait for enter-key for confirmation.
Note: The getch(), putch(), getche() are non-standard function, so it may not be available in all versions of C.
It works only on DOS based C-Software like Turbo-C.
getche(): it is just as getch(), but it shows the input character on the screen.
putchar(): this is similar to printf() function for showing single character on the screen.
putch():it sends the input character directly to the monitor buffer.
below three programs do same job, but last one is good choice.
void main() void main() void main()
{ char ch; { char ch; { char ch;
printf(“enter a alphabet :”); printf(“enter a alphabet :”); printf(“enter a alphabet :”);
ch=getchar(); ch=getchar(); ch=getchar();
if( ch>=’A’ &&ch<=’Z’) if( ch>=65 && ch<=90 ) if( isupper(ch) )
ch=ch+32; ch=ch+32; ch=tolower(ch);
else if( ch>=’a’ &&ch<=’z’) else if( ch>=97 &&ch<=122 ) else
ch=ch-32; ch=ch-32; ch=toupper(ch);
printf(“opposite is: %c”, ch); printf(“opposite is: %c”, ch); printf(“opposite is: %c”, ch);
} } }
always we can’t remember the Always we can’t remember This is the best choice to
ascii difference, this code is not asccii codes, this is not understand easily.
recommended recommended
C-Family 207 Characters & Strings
About fflush(stdin)
void main()
{ char ch1,ch2;
printf(“enter character1:”);
ch1=getchar(); or scanf(“%c”, &ch1);
printf(“enter character2:”);
ch2=getchar(); or scanf(“%c”, &ch2);
-----
}
input: enter character1: A ⤶ (A + enter-key )
unfortunately or unknowingly, we entered two input characters, first one is ‘A’, and second is ‘enter-key’.
In case of characters input, the ‘enter-key’ is also considered to be input value. Here first character ‘A’ will
be scanned by ch1=getchar(); whereas second character ‘enter-key’ will be scanned by ch2=getchar().
Here we need to clear the k.b buffer to avoid such unwanted character scanning. If you use fflush(stdin)
before reading 2nd character then it clears the ‘enter-key’ from the buffer so that next new character can be
scanned.
Let us see following program.
void main()
{ char ch1,ch2;
printf(“enter character1:”);
ch1=getchar(); or scanf(“%c”, &ch1);
printf(“enter character2:”);
ffush(stdin); // clears the enter-key input from the buffer
ch2=getchar(); or scanf(“%c”, &ch2);
-----
}
enter character1: A ⤶
enter character2: B ⤶
stdin represents keyboard buffer, stdoutrepresents monitor buffer, stdprnrepresents printer buffer.
fflush(stdin) clears the total keyboard buffer if anything there.
Example2:
printf(“enter character 1 & 2:”);
ch1=getchar();
ch2=getchar();
input: enter character1: AB⤶ (A + B + enter-key ) then here: ch1=’A’ and ch2=’B’ (works fine )
Example3:
printf(“enter character 1 & 2:”);
ch1=getchar();
ch2=getchar();
input: enter character1: A space B⤶ (A + space + B + enter-key ) then here: ch1=’A’ and ch2=space
Remember, ASCII value of space is 32, so 32 gets inserted in ch2.
C-Family 209 Strings
Strings
String is a collection of characters arranged sequentially one after the other in the memory, strings also said
to be array of characters, used to represent names of persons, items, countries, cities and sometimes to
represent messages. Generally, any non-computable data manipulates as strings. That is, on strings data, we
don’t do any arithmetical operation such as addition, subtraction, multiplication, division. To handle strings,
there is no direct data type in C, instead we have to access them as normal array of characters. However, C
provides some basic facilities to handle strings easily, such as representation of string constants,
initialization of string, automatic address generation of string constants and also provided several standard
library functions to manipulate the strings.
Example strings are “India”, “China”, “C-Family”, “123”, “A123”, etc.
The strings are stored like array of characters in the form of ascii values, and these ascii values are again in
the form binary values as computer understands it, for example, the string “INDIA” in the memory as
The string “INDIA” occupies 6 bytes in the memory ( 5bytes for INDIA + 1byte for null-character (‘\0’) )
The value ‘\0’ is taken as null-char and its ascii value is Zero, used to represent as ‘end-of-string-marker’.
The compiler automatically appends null character at the end of string constants.
What is string constant?
Like integer float char constants, we can represent string constants too. It is the set of zero or more
characters enclosed within a pair of double quotes is known as string constant.
Example for string constants: “India”, “C-family”, “A”, “”, “9440-030405”, “A123”, “1234”, etc.
Do not confuse 1234 with “1234”, the value 1234 is said to be integer constant, whereas “1234” is said to be
string constant (with quotes). The integer constant 1234 is stored in two-byte(int) of memory in its binary
format as: 00000100-11010010, whereas the string constant “1234” is stored in ascii form of every digit like
shown below.
Note: The ascii values of all chars lie in b/w 1-255, so this exceptional value 0 took as null-character-value as
a string terminator. But in programs, it is better to write ‘\0’ instead of 0(zero) to represent in symbolic way.
Note: Strings are nothing but character arrays, therefore, whatever operations applicable on arrays, they
can also applicable on strings. For example, printing, scanning, passing string to function, accessing string
through pointer, etc.
C-Family 210 Strings
String as variable
we know that, variable is a name of space, used to store and access a value with variable name. Similarly, to
store and access characters of a string, one is required “char []” array.
For example: char arr[20]; // It can hold a string with the maximum length 19 chars and 1 byte for null.
Initialization of strings: like normal arrays, we can initialize character arrays with the strings in
different ways. This is as given below example.
char a*9+=”C-Family”; // here null character automatically appends at end by the compiler
char a*+=”C-Family”; // the size of array calculates by the compiler, which is equal to length of “c-family”+1
char a[9+=, ‘C’, ’-‘, ’F’, ’a’, ’m’, ’i’, ’l’, ’y’, ‘\0’-; // we can initialize with char by char
char a*+=, ‘C’, ’-‘, ’F’, ’a’, ’m’, ’i’, ’l’, ’y’, ‘\0’-; // size not given, automatically calculated by compiler, it is 9
char a[]={67,45,70,97,109,105,108,121,0}; // we can also initialize with ASCCII values of “c-family”
The last declaration with ASCII values is somewhat confusion and not suggestible, it is just given for fun.
The First two declarations are more convenient & easy to understand.
char a[3+=”C-Family”; // compiler raises an error, because, the array size is not enough for the string
char a*20+=”hello”; // remaining 14 locations gets unused(empty)
Accessing individual characters in a string is same as accessing elements in the array. The index of the
character should be specified as array subscript.
For example: char a[10]=”C-Family”;
The expression ‘a*0+’ accesses the first character ‘c’,
‘a*1+’ accesses the second character ‘-’
‘a*2+’ accesses the second character ‘F’, …
in this way, we can access any element in the array
Console i/o functions on Strings
Input functions: scanf() , gets()
Output functions: printf() , puts()
gets() and puts() were provided simple syntax and specialized for strings data. The scanf() and printf() are
generic i/o functions, they support for all types such as int, float, long, string. Here format string %s is used
to read/write the string data.
① scanf(“%s”, array-address) : this reads a string char by char from keyboard until a new-line or a blank-
space is found, whichever comes earlier. If input is “ jack and jill⤶ ”, then scanf() accepts only “jack”.
② scanf(“%*^\n+”, array-address) : this reads a string char by char until new-line is found, that is, it accepts
total string including spaces. If input is “jack and jill⤶ ”, this scanf() accepts total string “jack and jill”.
The gets() and this scanf(“%*^\n+”, ..) works in similar way.
These input functions automatically append null character at the end of string. For example
input: A L L A P P L E S A R E R E D \0
void main()
{ char a[100]; int i, count=1;
printf(“\n enter a multi word string :”);
gets(a);
for(i=0; a*i+!=’\0’; i++)
, if( a*i+==’ ‘ ) // if space is found then count as one word
{ count++;
while( a*i+1+==’ ‘) // if next char is also space, then skip by incrementing loop.
i++;
}
}
printf(“\n number of words = %d”, count);
}
Let us observe the input string, contained more than one space between words. The inner while loop used
to skip extra spaces between words. When the index pointer ‘i’ moves to first space then ‘count’ increments
and all succeeding spaces if any are skipped by the inner while loop.
Converting each word first letter to upper case and remaining to lower case.
ip: all apples are good, some are in white color and some are in red color.
op: All Apples Are Good, Some Are In White Color And Some Are In Red Color.
(Let us assume, the words in a string are separated by single white space)
void main()
{ char a[100]; int i ;
printf(“enter string :”);
gets( a );
a[0]=toupper( a[0] ); // converting first character to upper case.
for(i=1; a*i+!=’\0’; i++)
{ if( a[i-1+==’ ‘ ) // if previous char is space then word started
a[i]=toupper( a[i] );
else a[i]=tolower( a[i] ); // if a[i] is not first letter of word then convert to lower
}
printf(“output string is %s ”, a);
}
C-Family 215 Strings
String constants
Heap
Data Global variables
Area
Area Static variables
Stack Auto variables
Area Function return address
The data area is again divided into two parts, heap area & stack area. In heap area, a permanent data items
like string constants, global and static variables are managed. Whereas, in stack area, the temporary local
variables and function return addresses are manipulated. (Refer the chapter storage-classes)
All string constants in a program are moved to data-area, whereas in the code-area their starting addresses
are substituted (pasted). In this way strings are mapped with their address in the program, let us see
following example
C-Family 216 Strings
Pointer to string
As we know, string can be in the form of variable or constant. In both cases, the strings are handled in
similar way. For example
a a[0] a[1] a[2] a[3] a[4] a[5] …
char a[20+=”Hello”; 2000 ‘H’ ‘e’ ‘l’ ‘l’ ‘o’ ‘\0’ --
char *p=”World”; 4000 2000 2001 2002 2003 2004 2005 2006
As per first declaration, we can say that, the string is in the form of variable. In later part of the program, we
can replace this string “Hello” by some other string, but new string length must be <20 chars (array-size).
As per second declaration, we can say that, the string is in the form of constant. The space allocation for
string “World” is exactly length+1(6 bytes), here first character address (&W) assigns to the pointer ‘p’.
Now using pointer ‘p’, we can read the string char by char. In later part of the program, we can replace this
string “World” by some other string, but the new string length must be the same or less of this “World”.
If new string length is more, then it crosses memory limits and causes the program crash. This Pointer
initialization widely used for string constants where no changes required in the future like company-names,
country-names, person-names, codes, labels…etc.
Pointer to a string is just like a pointer to an array, either the string may be a variable or constant. In both
cases, the characters are accessed in similar way. Observe the above picture. If pointer ‘p’ is pointing to first
char in a string, the expression ‘*p’ accesses the first char, *(p+1) accesses the second char, etc. As we know,
the expressions *p, *(p+1), *(p+2)... can be written in array fashion as p[0], p[1], p[2],etc. For example
void main()
{ char a[ +=”World”, *p;
p=a; // p=&a[0];
for(i=0; p*i+!=’\0’; i++)
printf(“%c”, *(p+i) or p[i] );
C-Family 217 Strings
after P++
2001 ‘W’ ‘o’ ‘r’ ‘l’ ‘d’ ‘\0’
4000 2000 2001 2002 2003 2004 2005
&a[0] ‘H’ ‘e’ ‘l’ ‘l’ ‘o’ ‘W’ ‘o’ ‘r’ ‘l’ ‘d’ ‘\0’
P a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8]
&a[0] ‘H’ ‘e’ ‘l’ ‘l’ ‘o’ ‘W’ ‘o’ ‘r’ ‘l’ ‘d’ ‘\0’
P a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8]
&C ‘C’ ‘-’ ‘F’ ‘a’ ‘m’ ‘i’ ‘l’ ‘y’ ‘\0’
P
&F ‘C’ ‘-’ ‘F’ ‘a’ ‘m’ ‘i’ ‘l’ ‘y’ ‘\0’
P
C-Family 218 Strings
As we know, the parameter declaration “char *p” in pointer style is informal and sometimes confusion.
Most of the programmers prefer array-like-pointer declaration as “char p*+”. This is formal and it tells that ‘p’
is receiving string address rather than single char address. This parameter declaration “char p*+” seems to be
an empty-array, many people think like that, but implicitly it is a “char *p” pointer. This declaration
provided for easy understanding and nothing more
While manipulating strings, we often need to perform some common operations like copying a string,
comparing, reversing, finding sub-string, converting text format to numeric, etc. As these operations are
common in programming and we prefer to abstract (hide) these tasks by writing separate functions for
each operation. The string library functions named strlen(), strcpy(), strcmp(), strrev(),etc are already exist
to cooperate the programmer instead of writing from low level. The following programs show, how string
library functions are developed and used. Here some sample user-defined functions are implemented to
know how library function works internally.
if(“Hello”==“Hello”) printf(“equal”);
else printf(“not equal”);
}
Output: not equal
not equal
Even though two array contents are same, the output will be ‘not equal’, because, unknowingly, we are
trying to compare base address of two arrays, if(x==y) is nothing but if( &x[0] == &y[0] ). As we know, two
arrays will not be located in the same location of RAM. So always not equal.
In second if-statement also, the base address of two strings if( &H== &H ) are compared and we get again
“not equal”. Because two string constants will not be located in the same location.
The solution is, compare char by char using loop, which is as given below
void myStrcmp( char x[], char y[] )
{ for( int i=0; x*i+ != ’\0’; i++)
{ if( x[i] != y[i] )
break;
}
return x[i]-y[i]; // returning ascii difference
}
If both strings are equal then returns 0, otherwise returns first un-matched char’s ASCII difference of two
strings. It return +ve, if string1>string2 in dictionary order(Alphabetical order) or else –ve.
For example, if two strings are:
“Hello” and “Hello” then returns (0);
“World” and “Words” then returns (‘l’-‘d’); // ascii difference is +ve , here World>Words
“Words” and “World” then returns (‘d’-‘l’); // ascii difference is –ve , here Words<World
The main() function to check the above function is
void main()
{ char x[50], y[50]; int k;
printf(“\n enter string 1 and string 2:”);
gets(x); gets(y);
k=myStrcmp(x,y);
if( k==0) printf(“string1 == string2”);
else if( k<0) printf(“string1<string2”);
else printf(“string1 > string2”);
}
The above function myStrcmp() can be written in pointer notation as
int myStrcmp(char *x , char *y)
{ while(*x && *x==*y)
{ x++; y++;
}
return *x - *y;
}
C-Family 221 Strings
Reversing a string
void myStrrev( char *a )
{ int i;
for(i=0; a*i+!=’\0’; i++)
{ // empty loop to calculate length, loop ends when ‘i’ reached to null char, finally ‘i’ contains length
}
for( j=i-1, i=0; i<j; i++, j--) // ‘i’ points to first element, ‘j’ points to last element in the string.
{ t=a[i]; // swapping
i j
a[i]=a[j]; ‘A’ ‘B’ ‘C’ ‘D’ ‘E’ ‘F’ ‘G’ ‘H’ ‘I’ ‘J’
A[0] A[1] A[2] A[3] A[4] A[5] A[6] A[7] A[8] A[9]
a[j]=t;
}
}
C-Family 222 Strings
void main()
{ char a[100];
myStrrev( a );
printf(“\n string after reversing %s”, a );
}
ip: ABCDEFGHIJ
op: JIHGFEDCBA
strcat()
here ‘cat’ means concatenation, it attaches one string at the end of another string. That is, it concatenates
two strings like addition.
syntax: strcat( string1, string2 ); // string1=string1+string2;
proto-type: char* strcat( char*, char* );
void main()
{ char a*20+=”Hello” , b*20+=”World”;
strcat(a,b);
printf(“output1 = %s”, a);
strcat(a,”India”);
printf(“output2 = %s”, a);
}
Output: output1=HelloWorld
output2=HelloWorldIndia
strrev()
it reverses the given string
syntax: strrev(string);
proto type: char* strrev(char*);
void main()
{ char a*20+=”Hello”
strrev(a);
printf(“output1 = %s”, a);
strrev(a);
printf(“output2 = %s”, a);
}
output1: olleH
output2: Hello
strcmp()
compares two string whether they are equal or not? If both strings are equal then returns (0), otherwise
returns “first un-matched characters ASCII difference in +ve or –ve”.
If returned +ve value, then string1>string2 in dictionary order (alphabetical order), or else string1<string2.
void main()
{ char a*30+=”Hello World”;
char b*30+=”Hello World”;
K=strcmp(a,b); // copies char by char including null.
if( k==0) printf(“string1==string2”);
else if(k<0) printf(“string1 < string2”);
else printf(“string1 > string2”);
k=strcmp(“xyz”, “abcdef”);
if( k==0) printf(“string1==string2”);
else if(k<0) printf(“string1 < string2”);
else printf(“string1 > string2”);
}
op: string1==string2
string1 > string2
C-Family 224 Strings
strcmpi() or stricmp()
It compares two strings, which is same as strcmp(), but it ignores the upper/lower case of alphabets.
Syntax: int strcmpi(string1, string2);
void main()
{ if(strcmpi(“DELHI", "delhi")==0)
printf("Both are equal");
else printf("Not equal");
}
Outputs: Both are equal
strncmpi() or strnicmp()
It compares two strings up to some specified number of characters, and also ignores the case difference.
Syntax: int strncmpi( string1, string2, no-of-chars-to-compare);
void main()
{ if( strncmpi(“Garden", "gardening",3) == 0 )
printf("Both are equal");
else printf(“Not equal");
}
Output: Both are equal
strupr()
It converts all lower case alphabets into upper case in a given string.
Syntax: strupr( string);
void main()
{ char a[]="Pens and Pads";
strupr(a);
printf("%s", a);
}
Output: PENS AND PADS
strlwr()
It converts all upper case alphabets into lower case in a given string.
Syntax: strlwr( string);
void main()
{ char a[]="Jack n JILL";
strtwr( a);
printf("%s", a);
}
Output: jack n jill
strchr()
It searches for a given character in a string, it searches one by one from first position towards end of string.
It returns first occurrence of a specified character address if it is found. Otherwise it returns NULL value.
Syntax: char* strchr(string, char to search);
void main()
{ char *p;
p=strchr("Hello world", ‘w’); // returns “&w” in “hello world” string.
printf("%s", p);
}
C-Family 225 Strings
This printf() will prints the message "world" , because ‘p’ pointing rest of the string “world”
&a[6] ‘H’ ‘e’ ‘l’ ‘l’ ‘o’ ‘W’ ‘o’ ‘r’ ‘l’ ‘d’ ‘\0’
P a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9] a[10] a[11]
strstr()
it searches for a sub-string in a main-string. It returns the first occurrence of sub-string address if it is found.
Otherwise, it returns NULL, if not found.
void main()
{ char *p;
p=strchr("I like you very much", “you”);
printf("%s", p);
}
This printf() will print the message "you very much"
&a[6] ‘I’ ‘ ’ ‘l’ ‘i’ ‘k’ ‘e’ ‘ ’ ‘y’ ‘o’ ‘u’ ‘ ’ ‘v’ ‘e’ ‘r’ ‘y’…
P a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9] a[10] a[11] a[12]
atoi()
It converts a string-value to integer-value.
Syntax: int atoi(string);
Example: int k;
k= atoi("123")+atoi("234");
printf(" output = %d", k);
output will be: 357
atol()
Converts string-value to long-int value
Syntax: long int atol(string);
Example: long int k;
k= atol("486384")-atol("112233");
printf(“output = %ld”, k);
output will be = 374151
atof()
Converts floating point text format value to double value.
Example: float f;
f=atof("3.1412")*5*5;
printf(“%f “, f);
output will be: 78.530000
itoa(),itoa(),ultoa()
These functions converts a given number (int/long int/unsigned long int)equivalent to string format based
on the given numbering system radix value.
These functions take three arguments, the numeric value, target string address in which the value to be
stored and radix value. Finally returns the target string address, so that function-call can be used as
argument/expression.
To store a group of strings, we need a data structure like 2-dimensional array with N*M size, where N is
number of strings and M is maximum size of string length.
Initializing N strings
char a[10][20]={ “APPLE”, “ORANGE”, “BANANA”, “ GUAVA”,…etc};
We can imagine, how the strings are stored in 2D array
Recursion
Calling a function within the same function is called as recursion. It is the process of defining something in
terms of itself, and sometimes also called as circular definition.
The syntax, the usage, and the execution of recursive function is just like any normal function. There is no
technical difference between recursive and normal function. However, for beginners, the logic of recursion
is somewhat difficult to understand and writing programs in it. The major confusion is, understanding the
logic regarding self-calling, self-returning, and how the arguments & local variables are managed in
recursive-calls. If you are familiar with functions, here by observing some simple examples we can follow the
logic easily. Here some examples explained with pictures to understand the basic concept of recursion.
Before going to examples, let us see some mathematical analysis on recurrence relations.
1) f(n)=n+n/2+n/4+n/8+….+1
the recurrence relation is:
f(n)=n+f(n/2) if n>1
f(n)=1, if n==1
2) fact(n) = n*n-1*n-2*….3*2*1
the recurrence relation is:
fact(n)=n*fact(n-1), if n>1
fact(n)=1, if n==1
=======================================================================================
First demo program
void main()
{ printf(“hello ”);
main(); // self-calling (recursive-call )
}
output: hello hello hello hello … until stack overflow (memory full)
Here the main() fn called recursively inside its body, therefore the control re-enter into same body again and
again as it repeatedly calling again and again(), it prints “hello” many times, but in every recursive call some
memory is consumed by operating system(OS) to store function-return-address, so after some calls, the
memory gets full and program stopped forcefully by OS. This force stop is also called program crash. This is
just a demo program and I am trying to say about recursion.
Let us see, how local variables behave inside recursive function.
C-Family 231 Recursion
void main()
{ int k=1; call-1 of k call-2 of k call-3 of k call-x of K
if( k==5)
return;
printf(“%d ”, k );
k++;
main(); // self-calling (recursive-call)
}
Here we expect the output 1, 2, 3, 4, but it is wrong. It shows 1, 1, 1, 1, 1, … until memory is full. For every
recursive call, one new copy of ‘k’ is created and initialized with 1(as above pic). So output is 1, 1, 1, 1…..
Here the k value never reaches to 5, because the ‘k++ incremented’ value at one call, will not be affected to
next call of ‘k’, so always prints 1,1,1,1….. until memory is full.
Note: as new copy of ‘k’ is created in every call, the memory gets full after some calls and OS stops our
program.
Points to understand Recursion
When a recursive function is called itself, the programmer should be treated as, he is calling another
function(copy) of same code as shown in the below figure. Of course, in the memory, same function
body will be executed like a loop.
For every recursive call, one set of local variables (in this example ‘k’) are created and available up to
that call is terminated. That is, when such call is terminated, all local variables are freed (deleted).
Recursive function executes like a loop statement, as we know, every loop has a terminating condition,
in the same way, to stop the recursive calls, there must be a termination condition and it is often called
base condition. Generally, it appears at the beginning of function (we will see in the next examples).
This figure explains how the recursive calls should be imagined for above example
*Here in every recursive call, one fresh copy of ‘k’ is created initialized with 1, the incremented k++ will not
be affected to next call. So output is 1 1 1 1….
Taking ‘k’ as parameter instead of local variable, let us see following examples
C-Family 232 Recursion
void main()
{ display(1);
}
st nd rd th
1 call, here k=1 2 call, here k=2 3 call, here k=3 4 call, here k=4
void display( int k) void display( int k) void display( int k) void display( int k)
{ if(k==4) { if(k==4) { if(k==4) { if(k==4)
return; return; return; return;
printf(“%d “, A ); printf(“%d “, A ); printf(“%d “, A ); printf(“%d “, A );
printf(“%d “, B ); printf(“%d “, B ); printf(“%d “, B ); printf(“%d “, B );
display(k+1); display(k+1); display(k+1); display(k+1);
printf(“%d “, C ); printf(“%d “, C ); printf(“%d “, C ); printf(“%d “, C );
printf(“%d “, D ); printf(“%d “, D ); printf(“%d “, D ); printf(“%d “, D );
} } } }
* The last closing braces of function works as ‘return‘ statement, observe above shown picture.
* Here 4th call returns to previous 3rd call, and 3rd call returns to previous 2nd call, in this way recursive calls
are returned & terminated. The above picture is the best view how the recursive calls can be imagined.
* In recursive function, all instructions which are above recursive-call are executed just before going to
next call, so output is AB AB AB, and all below instructions are executed just before returning to
previous call, so output is CD CD CD.
* The main difference between loop and recursion is, loop works on single data set variables, whereas
recursion works on multiple data set variables.
C-Family 233 Recursion
*Printing 1 2 3 3 2 1 recursively
void main()
{ display(1); // passing argument 1
}
void display(int k)
{ if(k==4) return;
printf("%d ", k); // printing output before going to next-call
display(k+1);
printf("%d ", k); // printing output after coming back from next-call
}
Here the output '1 2 3' prints by first printf(“%d “, k), whereas second output '3 2 1' prints by second
printf(“%d “, k) statement. The first printf() executes just before next call is made. Whereas second printf()
executes after returning from next-call.
This figure shows how the output 1 2 3 3 2 1 prints on the screen.
void main()
{ display(1);
}
st nd rd th
1 call, here k=1 2 call, here k=2 3 call, here k=3 4 call, here k=4
void display( int k) void display( int k) void display( int k) void display( int k)
{ { { {
if(k==4) if(k==4) if(k==4) if(k==4)
return; return; return; return;
printf(“%d “, k); printf(“%d “, k); printf(“%d “, k); printf(“%d “, k);
display(k+1); display(k+1); display(k+1); display(k+1);
printf(“%d “, k); printf(“%d “, k); printf(“%d “, k); printf(“%d “, k);
} } } }
Complete the following code to print output as shown below(do not use loops)
123456789
123456789
------
5 rows
void main()
{ int rows=5; // [Link] rows to print
show(rows);
}
void show( int row)
{ ------
printRow( 9 ); // this function prints 1 to 9 values of a row
------ // call show() recursively 5 times, for 5 rows
}
void printRow( int i )
{ if(i==0) return;
printRow( i-1 );
printf(“%d “, i ); // prints each row here
}
C-Family 237 Recursion
int find(int n) int find(int n) int find(int n) int find(int n) int find(int n)
{ { { { {
if(n==0) if(n==0) if(n==0) if(n==0) if(n==0)
return 0; return 0; return 0; return 0; return 0;
return 7+find(n-1) ; return 7+find(n-1) ; return 7+find(n-1) ; return 7+find(n-1) ; return 7+find(n-1) ;
} } } } }
Note: Myself, I solved many problems in recursion, but most of result calculating functions comes under
above two logics only. this logic is better than above program logic.
First call (n=4) Second call (n=3) Third call (n=2) Fourth call (n=1)
Finding factorial in iterative process (using loop) is simple & easy compared to recursion. This is just a
demo program to explain the logic of how the recursion executes.
The last call returns ‘1’ and it is substituted in its previous-call, the previous-call again returns ‘2*1’ and is
substituted in its previous call. In this way, the final result 24 is returned to main() fn.
First call ( x=2, y=3 ) Second call ( x=2, y=2 ) third call ( x=2, y=1 ) Fourth call (x=1 , y=0)
int power(int x, int y) int power(int x, int y) int power(int x, int y) int power(int x, int y)
{ { { {
if( y==0 ) if( y==0 ) if( y==0 ) if( y==0 )
return 1; return 1; return 1; return 1;
return x*power(x,y-1); return x*power(x,y-1); return x*power(x,y-1); return x*power(x,y-1);
} } } }
x y x y stop
12 ) 18 ( 1 6 ) 12 ( 2
12 12
6 0
void main() int GCD( int x, int y ) int GCD( int x, int y )
{ int k; { {
if(y%x==0) if(y%x==0)
k=GCD(12 , 18); return x; return x;
return GCD( y%x , x) ; return GCD(y%x , x);
printf(“\n gcd=%d”, k); } 6 }
}
k=6 return(6) return(6)
void main()
{ printf("enter how many no of terms to print:");
scanf("%d", &n);
fibo(n);
}
output: 0 0 0 0 0 0 0 0 0 0 0 0 0…… (Wrong output)
The above function produces wrong output. Because, for every recursive call, one fresh copy of local
variables x &y are created and initialized with 0 and 1. (We already discussed many times)
To solve this problem take x,y as parameters and pass one-call updated values to next-call.
This is shown below
void fibo(int x, int y, int count)
{ if(count==0) return; // repeat until ‘count’ down to 0.
printf("%d ", x );
fibo( y, x+y, count-1);
}
void main()
{ int count;
printf("enter how many no of terms to print:");
scanf( "%d", &count );
fibo( 0, 1, count );
}
In this program, one may think that, only one copy of x & y is enough for all calls rather than
creating a fresh copy in every call. So to avoid more copies, we can declare x, y as
static/global. But this creates another problem! Once the static/global variable is created, it
will not be killed even after function call ends; moreover they cannot be reinitialized for
int k=1;
upcoming calls. Let us have one more example with global variable
int k;
void main()
{ show(); // at this call, output is 1 2 3 4
show(); // at this call, no output
}
void show()
{ if(k==5) return;
printf(“%d “, k);
k++;
show();
}
op: 1 2 3 4
we expect output as 1 2 3 4 1 2 3 4 [ as two times show() fn called from main() fn ], as ‘k’ is global variable,
only one copy is created and shared to all calls. After printing 1 2 3 4 at first call, the k attains 5 and will not
be re-initialized to 1 for next calls. So no output is displayed for next calls. As per this experience, we don’t
recommend static and global variables in the recursion.
C-Family 242 Recursion
Fibo(5) fibo(4)+fibo(3)
fibo(4-1)+fibo(4-2)+fibo(3-1)+fibo(3-2)
fibo(3-1)+fibo(3-2) + fibo(2)+fibo(2)+fibo(1)
fibo(2)+fibo(1)+fibo(2)+fibo(2)+fibo(1)
1+0+1+1+0 3
C-Family 243 Recursion
void main()
{ int n=5;
x=find(n);
printf(“ the Nth term = %d”, x);
}
int fibo( int n)
{ if(n<=2) return(n-1);
return fib(n-1)+fibo(n-2);
}
Observe the following figure and try to understand how recursive calls are made.
int fibo( int n : 3) int fibo( int n : 2 ) int fibo( int n : 1 ) int fibo( int n : 1)
{ if(n<=2) { if(n<=2) { if(n<=2) { if(n<=2)
return(n-1); return(n-1); return(n-1); return(n-1);
return fibo(n-1)+fibo(n-2); return fibo(n-1)+fibo(n-2); return fibo(n-1)+fibo(n-2); return fibo(n-1)+fibo(n-2);
} } } }
While terminating function calls, the following statements are gets executed
return (2+1)
int main()
{ char a[]= "ABC";
permute(a, 0, strlen(a)-1 );
}
void permute(char a[ ] , int i, int len)
{ int j;
if(i==len)
{ puts(a); return;
}
for(j=i; j<=len; j++)
{ k=a[i]; a[i]=a[j]; a[j]=k; // swapping a[i], a[j]
permute(a, i+1, len);
k=a[i]; a[i]=a[j]; a[j]=k; // swapping a[i], a[j]
}
}
If an application is very complex, having rare usage, and taking less space for local variables, then it is better
to implement recursive rather than non-recursive. Recursive is simple and easy to code
It is the programmer’s choice, which method is to be used when and where. If execution time and space are
not constraints, then it is better to implement recursive application.
Implementation of recursion nature problem in non-recursive using loop and stack is an advanced concept.
That topic is beyond the scope of this book.
C-Family 246 Recursion
C-Family 247 Dynamic Memory Allocation
Here compiler creates 206 bytes for int a, b, c[100], d. It adds instructions for allocation & de-allocation of
memory as shown above. [ It creates memory in stack as [Link](206) and [Link](206) ]
The static allocation system is much suitable when we know the size of data like employee-name(25 chars),
address(50 chars), pin-code(long-int=4 bytes), phone-number(long-int 4 byte),…
In the above example, the function ‘malloc()’ allocates 10 bytes of memory in the RAM and returns the
starting byte address, which is then assigned to 'p'. Here one question arises! What type of pointer ‘p’
should be? This is fairly depends upon what type of data which we are going to keep in this memory.
Suppose if you are going to store array of float values then pointer should be “float*” type. Remember that,
malloc() returns just address which has no specific type, that is, it returns “void*” type address. So it should
be type-casted as per our pointer type. (All these functions return-type is void* type only)
float *p; P
p[0] P[1] P[2]
*p *(p+1) *(p+2)….
scanf(“%d”, &N); 2000
p=(float *)malloc( N * sizeof(float) ); 4000 2000 2004 2008….
calloc()
It is also like malloc(), but after allocation of memory, it clears the garbage values by filling with zeros in all
bytes of memory.
pointer = calloc ([Link] items, size of item );
It takes two arguments, first one is number of items to be allocated and second one is size of item. For
example, allocating memory for 5 floats
float *p;
p = (float *) calloc(5, sizeof(float));
realloc()
It is used to resize (reduce or expand) the memory which is already allocated using malloc() or calloc() or
realloc(). It takes previously allocated memory address and adjusts to new size.
While expanding the size of old memory, if required amount of memory is not available at the adjacent
locations, then it allocates in new location and copies the old memory contents to new location and then
releases the old memory. If the memory is not available, then it returns null.
free()
It is used to release the memory which is no longer required by the program. This memory should not
belongs to static allocated system like “int a[10]”. This must be a dynamic memory which is allocated by
malloc() or other functions. It takes the base address of memory as an argument and frees it.
Prototype: void free(void *);
Syntax: free(address);
Example: int *p;
p=(int *)malloc(50*sizeof(int));
---
---
free(p);
C-Family 250 Dynamic Memory Allocation
“Pakistan”
“Srilanka”
C-Family 251 Dynamic Memory Allocation
When a program is run, the operating system loads .exe file into memory and invokes the startup function
main(). Here, we can assume the OS is the caller of main() function. Therefore, the arguments can be passed
to the main() by specifying a list of values at the command line as shown below.
C:\tc\bin\>sum 10 20 30
Unlike other functions, the arguments to main() passes in a different manner. They pass as array of string
constants. That means, even if you give an integer values, they pass as strings. In the above case also, the
arguments will be passed as "sum”, "10", "20", "30". (Passes as array of addresses as shown in below
picture).
But main() receives them as two arguments, the first argument is integer, which specifies the count of
arguments which we passed including file-name. The second argument is, an array of addresses containing
strings. Thus main() function should be defined as
Example1 : this program adds all such integers which we passed through command line as above shown
Input: c:\tc\bin\> sum 10 20 30 40
Output: sum of numbers = 100
void main( int count, char *a[ ] )
{ int sum=0,i=0;
for(i=1; i<count; i++)
sum = sum+atoi(a[i]); //atoi() function converts numeric string to integer value
printf("\n sum of numbers = %d", sum);
}
Example2: The following program takes string as input from command line and displays length.
It also shows an error, if user enters less number of strings.
Input: C:\tc\bin\>sample C-Family
Output: length of C-Family = 8
void main( int count, char *a[] )
{ if( count==1)
{ printf(“insufficient arguments”);
return;
}
prinf(“the length of %s = %d”, a*1+, strlen(a*1+) );
}
C-Family 252 structures, unions, enums
Primitive Data types: these are also called built-in or basic types, for example int, char, float, int*, etc;
these primitive types and their functionalities were already designed and developed in compiler level during
development of C software. Therefore, we can directly use them in programs.
User defined Data types: ‘C’ gives a freedom to the coder to define his own data types according to
requirement in the program. Therefore, these are called user-defined types.
We have 3 types, ①structure ②union ③enumerator.
Generally, it is difficult to handle large collection of data using basic types. Using arrays, we can handle only
collection of homogeneous items of known size. However, to handle collection of heterogeneous items then
user-types are required. For example, consider an employee data containing id, name, address, salary, etc.
Handling such heterogeneous items individually is difficult and leads to complex task. If we group all these
items into single (as one record) then they can be handled easily. For this, fortunately, C is providing a
structures concept.
1) Structures
Structure is a collection-type user-definedstruct structure-name
data-type, variable1,
used to pack several variable2,…,
different items together as single
variableN;
item. So we often state that, array is collection of homogenous items, whereas structure is a collection of
heterogeneous data items. Sometimes, the items in a structure can be same type.
The items in a structure are called data-members and we can have as many members as we want.
Syntax to declare a structure
struct structure-name
{ data_memberl;
data_member2;
…
data_memberN;
};
For example:
struct student
{ int idno;
char name[30];
int marks1, marks2;
};
This structure declaration defines or creates a new data-type called “struct student”, using this, we can
create variables and its data can be managed.
This structure declaration works as a blue-print or template of our type and it does not occupy any space in
executable file. Just it gives layout idea to the compiler i.e, about structure-name, data type of each member
and space required for each member. Now using this structure template, we can create variables and its
data can be managed. Here structure-name is the name given to the structure and it follow rules of variable
naming. The structure can be declared in local or global scope, depends upon requirement of program.
C-Family 253 structures, unions, enums
Many people says, the declaration of structure works as logical idea like building plan on paper whereas the
variables of structure works as physical space like constructed building. (logical vs physical or plan vs
implementation)
Accessing members in a structure: we have two operators
1. Selection operator, dot (.) // accessing through structure variable
2. Indirect selection operator, arrow () // accessing through structure pointer
a) Using selection operator
syntax: struct_variable . member_name K
100 “Lokesh” 45 78
for eg: the expression [Link] accesses the ‘idno’ in K
[Link] [Link] k.mark1 k.marks2
the expression [Link] accesses the ‘name’ in K
the expression K.marks1 accesses the ‘marks1’ in K
printf(“ %d %s %d %d ”, [Link], [Link], K.marks1, K.marks2);
P K
2000 100 Lokesh 45 78
pid pname pmark pmarks2
Note: the expression (*p).name cannot be taken as *[Link], because, the dot operator(.) has high priority
than pointer operator(*) , here first the compiler tries to evaluate [Link] thereby shows an error. Because
‘p’ does not have members of a structure, actually it contained address. The expression (*p).name is valid
expression because it is ‘[Link]’
C-Family 254 structures, unions, enums
K S
100 Lokesh 33 44 101 Srihari 55 66
B) Assignment of structure members is same as assigning values to basic data- type variables, for example
[Link]=100; // filling idno number with 100
[Link]=”Srihari” ; // we can’t assign like this, because ‘name’ is arrays’s pointer
strcpy([Link], “Srihari”); // filling name with “Srihari”
K.m1=66;
K.m2=77; // filling marks with 66,77
Scanning two dates from KB and finding whether they are equal or not?
* trying with & without using functions
ip: 12 9 2010 ip: 12 9 2010
12 9 2010 13 9 2011
op: equal op: not equal
struct Date
{ int d, m, y;
};
void main()
{ struct Date a , b;
int k;
read( &a ); // scan date1 (day, month, year) using read() function.
read( &b ); // scan date2 (day, month, year)
k=compare( a , b ); // compares two dates and returns 1/0
if( k==1) printf("equal");
else printf("not equal");
}
void read( struct Date *p )
{ printf("enter day month year:");
scanf("%d%d%d", &p->d, &p->m, &p->y);
}
int compare( struct Date p , struct Date q )
{ if( p.d==q.d && p.m==q.m && p.y==q.y )
return 1;
else
return 0;
}
the read() fn followed call-by-reference, because, the scanned values at read() fn need to be returned to
main() fn, therefore we have to store indirectly through pointers, whereas compare() fn follows call-by-
value, it is just comparing given two dates.
struct Time
{ int h, m, s ;
};
void main()
{ struct Time a, b, c;
a=read(); // this read() fn returns the scanned time ( it is opposite to above read() fn)
b=read()
c=add(a,b); // add two times like c=a+b
write(c); // print output time on the screen
}
C-Family 257 structures, unions, enums
Scanning two matrices data from keyboard(KB) and printing addition of them
struct matrix
{ int a[10][10]; // array to hold matrix elements
int r,c; // r, c are order of matrix
};
void main()
{ struct matrix x, y, z;
int k;
accept(&x); // call-by-reference
accept(&y);
k=add(&z, x, y); // partly call-by-value and call-by-reference
if(k==0) printf("\n Matrix cannot be added ");
else display(z); // call by value
}
void accept( struct matrix *p )
{ int i,j;
printf("Enter [Link] rows and columns :");
scanf("%d%d", &p->r, &p->c );
for(i=0; i<p->r; i++)
{ for(j=0; j<p->c; j++)
{ printf("enter value of [%d][%d]:", i, j);
scanf("%d", &p->a[i][j]);
}
}
}
void display( struct matrix z)
{ int i,j;
for(i=0; i<z.r; i++)
{ for(j=0; j<z.c; j++)
printf("%d ", z.a[i][j]);
printf("\n");
}
}
int add(struct matrix *p, struct matrix x, struct matrix y)
{ int i,j;
if(x.r != y.r || x.c != y.c)
return 0; // zero indicates addition failed
for(i=0; i<x.r; i++)
for( j=0; j<x.c; j++)
p-> a[i][j] = x.a[i][j] + y.a[i][j];
p->r=x.r;
p->c=x.c;
return 1; // return ‘1’ indicates addition succeeded
}
C-Family 259 structures, unions, enums
Array of structures
Array of structures is useful when several instances of details are to be handled in the program.
We can create array of structures just like any normal data types.
Syntax: struct structure-name array-name[size];
For example: struct Person
{ char name[20]; // name of person
int age // age of person
};
struct Person s[3]; // creates array of 3 structure variables.
Like normal arrays, the structure arrays are accessed, here each element s[0], s[1], s[2] is a structure item.
Syntax to access members in the structure array is: array-name[index].member-name
The expression s[0].name accesses the name in s[0]
The expression s[0].age accesses the age in s[0]
The expression s[1].name accesses the name in s[1]
The expression s[1].age accesses the age in s[1]
Following program explains how to scan & print array of 3 structure values.
void main()
{ struct Person s[3];
scan(s); // scan(&s[0] ) passing base address of array
display(s); // display(&s[0]); passing base address of array
}
void scan(struct person p[] or struct person *p)
{ int i;
for( i=0; i<3; i++)
{ printf(“enter name & age of a person :”);
gets(&p[i].name); // gets( (p+i)->name );
scanf(“%d”, &p*i+.age); // scanf(“%d”, &(p+i)->age );
}
(or) for( i=0; i<3; i++)
{ printf(“enter name & age of a person :”);
gets(&p->name);
scanf(“%d”, &p->age);
p++; // increments by 22, to points to next structure in the array
}
}
void display ( struct person p[] or struct person *p )
{ int i;
for( i=0; i<3; i++)
{ printf(“\n %s %d “, p*i+.name, p*i+.age); //or printf(“\n %s %d “, (p+i)->name, (p+i)->age);
}
(or) for( i=0; i<3; i++)
{ printf(“\n %s %d “, p->name, p->age);
p++; // increments by 22, to points to next structure in the array
}
}
above two loops do same job in scan() & display() functions, but second loop little faster than first loop.
C-Family 260 structures, unions, enums
Nested structures
Structure in structure is said to be nested structure, we can nested as many times as we want, complexity
will not be increased even though nested many times. For example,
struct Student
{ int idno;
struct Date
{ int d,m,y;
} joinDate;
};
void main()
{ struct Student p;
[Link]=10; P
[Link].d=10; Idno joinDate
[Link].m=12; d m y
[Link].y=2020;
-----
}
typedef
“typdef” is a keyword,used to define new convenient names for existing data types.
The new-name works as alias-name for existing data types, but we don’t lose the old- name.
Syntax: typedef existing-name new-name;
typedef float RS;
typedef float DOLLOR;
typedef int* INTP;
Let us see, how variables can be declared
RS amount1; equal to: float amount1;
DOLLOR amount2; equal to: float amount2;
Here amount1 & amount2 are nothing but float type variables and this is equal to
float amount1, amount2;
Similarly, structure types can be declared in two ways.
struct Date
{ int d,m,y
};
typdef struct Date DATE; //now DATE is a convenient name of struct Date;
Advantages of a structure
1. Easy to access member in a structure:
Using structure variable, it is easy to access each member rather than when are in individual, which gives
more clarity and easy to handle.
2. Assignment between structures is possible
the compiler supports for copying one structure to another structure just like any integer value.
Here all members in the structure are copied bit by bit.
Unions
Union defines the generic data-type instead of specific type, where we can store any type of value such as
int/float/char/etc. The main purpose of union is to save the memory space, and also gives flexibility in
coding. Union is also similar to structure but all the members in the union share the common memory area.
Here space is created for only one member and remaining members share the same space, therefore we can
store & access only one member at a time. The size of union is equivalent to biggest data member in it.
Note: this is used while developing customized-packages or frame-works for one language. (Not in student
level programming)
item
union myType
{ char c; Byte1 Byte2 Byte3 Byte4
int i;
long int l; c
i
float f;
f/l
};
union myType item;
The above union variable ‘item’ occupies 4bytes of memory. Among 4 members, the first member ‘c’ uses
only first byte. The second member ‘i’ uses first two-bytes. Similarly remaining f & l uses total 4bytes.
Here only one item can be stored & retrieved at one moment.
C-Family 265 structures, unions, enums
In the above program, when ‘var.i’ is assigned a value 10, the other union members ‘var.j’ and ‘var.k’ also
gain the same value as they are sharing the common memory space.
void main()
{ union myType var;
var.i=10;
var.j=20;
var.k=30;
printf(“\n i=%d j=%d k=%d", var.i, var.j, var.k);
}
op: 30 30 30. Here var.j=20 overwrites the var.i=10, var.k=30 overwrites var.j=20;
Let us see one more example
union myType
{ long l;
float f;
};
void main()
{ union myType var;
var.f=200;
printf("\n l=%ld f=%f\n", var.l, var.f);
var.l=100; // overwrites var.f=200 value
printf("\n l=%ld f=%f\n", var.l, var.f);
}
Output: l=garbage f=200.000000
l=100 f=garbage
Let us see practical example, the print() function can print all types of data.
typedef struct
{ union
{ char cc;
int ii;
float ff;
}value;
char valueType;
}MyType;
void main()
{ MyType var;
[Link]='A';
[Link]='c';
print(var);
[Link]=100;
[Link]='i';
C-Family 266 structures, unions, enums
print(var);
[Link]=300.45;
[Link]='f';
print(var);
}
void print(MyType var)
{ switch([Link])
{ case 'c':
case 'C': printf("\n%c", [Link]); break;
case 'i':
case 'I': printf("\n%d", [Link]); break;
case 'f':
case 'F': printf("\n%.2f", [Link]); break;
}
}
Enumeration
Enumerator data type is used to symbolize a list of constants with names, so that, it makes the program easy
to read and modify. Enumerator maps the values to names there by we can handle the values with names.
enum enumerator-name { name1=value1, name2=value2, name3=value3, ... nameN=valueN } ;
Let us see one program: this program displays [Link] days in a given month.
enum month { jan=1, feb=2, mar=3, apr=4, ….-;
void main()
{ int mon;
printf(“enter month number(1-12):");
scanf(%d",&mon);
switch(mon)
{ case jan: printf(“ January month has 31 days"); break;
case feb: printf(" February month has 28 days"); break;
case mar: printf(" March month has 31 days"); break;
---
}
}
Here all month names are replaced by its constant value at compile time, so the enumerator set symbols are
evaluated of above program is
void main()
{ int mon;
printf(“enter month number(1-12):");
scanf(“%d",&mon);
switch(mon)
{ case 0: printf(“ January month has 31 days"); break;
case 1: printf(" February month has 28 days"); break;
case 2: printf(" March month has 31 days"); break;
---
}
}
C-Family 267 structures, unions, enums
Ambiguity error
There is one problem with enumeration, if any variable exist with same name in enumerator set in same
scope then we get error at compile time.
For example,
enum color { red, green, blue, white, yellow};
int red=0; // ambiguity error with red, so either one must be removed
void main()
{ int white=100; // preference is given to local white variable, instead of white in enumeration
printf("%d %d %d %d", green, blue, white, yellow};
}
output: 0 1 100 4
Enumeration variables
Using enumerator name, we can specify variables of its type. This makes the convenient and increases the
readability of the program. The enumerator variables are nothing but int-types. For example
enum enumerator-name variable-1 ,variable-2, variable-3, ... ;
enum Color { Red=15, Green=26, Blue=13, White=5, Yellow=4, Grey=17 };
void main()
{ enum Color wallColor, floorColor;
wallColor=White;
floorColor=Grey;
…
…
}
C-Family 268 Data Files
File handling in C
In real life applications, some kind of data needs to be accessed more times in present and future purpose
like bank transactions, business transactions, etc. Therefore such data is kept permanently in the computer,
so that it can be accessed many times later.
For this purpose, secondary storage devices are used to store the data permanently in the form of files.
These files often called data files. Thus, data file can be defined as collection of data, stored permanently in
secondary storage device. Each file is identified by a valid name called file-name. The interaction with files is
treated as interaction with io devices in the computers. Therefore, all secondary memory devices treated as
io devices.
Let us consider a menu driven program to automate student marks in a college. Let the marks scanned from
keyboard are stored permanently in a data file called "[Link]", later, such marks are processed and
stored the results in a separate file called "[Link]" or displayed on the screen. This is depending upon the
requirement of problem. Following picture explains how our programs interact with files.
Program3 Monitor
Input file1: “[Link]” void main() Displaying record(s) on the screen.
{
----
---- Printer
Input file2: “[Link]”
} Printing record(s) on the printer.
1. Text Format Files: Here the data is stored in the form of ascii values (string format)
2. Binary Format Files: here the data is stored as it is in program variables (raw format))
C-Family 269 Data Files
Text Files
In text files, everything is stored in the form of ascii values, even numeric data is converted into string
format with its ascii values of each digit and stored in file. For example, 'k' contained a value 2891, this
number is stored in text file as
Here 50, 56, 57,49 are ascii values of 2, 8, 9,1 respectively. Internally each digit ascii code is again stored in
binary form as above shown (as computer understands only binary values), in this way, the text data is
stored and retrieved from text files. These files are only suitable for public sharing related files such as
document files, help files, message files, source code program files, small data files, configuration files, etc.
In general, these files are handled in two ways, by writing a specific program to manage them, or by using
ready-made text editors. Using text editor, we can create & modify the text data. We have several text
editors like notepad, word pad, ms-word, etc.
The value 26 is inserted as end-of-file mark and also the new-line character is stored as "\r\n"(unix format).
The library functions does this job while writing ‘\n’ to file, whereas while reading back, it is considered as
only one character (\n). (We need to worry about this ‘\n’)
Some people raise a doubt, if file data itself contained 26 like employee age, then how it differentiates with
the end-of-file 26. Our 26 is stored as ‘2’ and ‘6’ as its ascii values 50 & 54, so no conflict between these two.
Binary files
In this kind of file organization, the data is stored as it is in program variables. Here no conversion is made
while storing and reading back unlike text files. Generally, binary files are extensively used for maintaining
similar type of data like employee records or bank accounts, insurance accounts, etc.
In binary i/o, as it is of storing & reading back takes place between the RAM & hard disk, therefore binary
files are faster than text files. At end of text files, the value 26 is inserted as end-of-file-mark, whereas in
binary files no such value is inserted, where end-of-file mark is known by the file-size.
In case of binary files, we cannot manipulate the data using text editors. For example, take student structure
idno|name|marksint|char(30)|int. if this data dumped as it is into file, then it has to be read back as it is.
(2byte at a time for idno, 30byte at a time for name,..) So, text editors unaware of this user-defined
structure, hence we cannot handle binary files using text-editors.(text editors are designed to read/write the
data only in the form of ascii values)
There should be separate software needed to handle binary files. For example ‘pdf’ file is a binary format file
and cannot be opened in text editor, a special software like Adobe-Reader is used. Similarly, jpg files, image
files, sound files, movie files are managed using special software.
In C, files can be handled in two ways, 1. High Level file handling, 2. Low Level file handling.
In high level file handling, there are plenty of library functions with file streaming is available, here C
provides more support like reading/writing of text/binary data from file, converting numeric to text, text to
numeric, interaction with printer, random file organization, checking end-of –file pointer, etc. So it is easy to
handle files in high level organization, but in low level, there is no library functions support, here we need to
write the code from zero level. This low level is used in hardware industries for chip level programming to
develop customized softwares (packages), drivers, utilities. Etc.
C-Family 270 Data Files
High-level file IO
Operations on files are mainly three
1. Opening a file
2. Applying read/write/modify operations on file data
3. Closing a file
Opening a file: The function fopen() is used to open a file, when we open a file, the file contents are
dumped from hard-disk to RAM and then file pointer set to it. The function proto-type is
FILE* fopen(char *fileName, char *openMode);
The first argument is the name of file which we want to open, and second argument is opening mode.
For example: FILE *fp; // pointer to FILE structure
fp=fopen("[Link]" , "rt"); // r: read-mode, t: text-file
when a file is opened in the RAM then its memory picture as given below structure
Pointer
to file
this FILE structure holds file stream data
File Pointer to Pointer to current Open mode File type Block Error
name file data block read/write record (read/write) (text/binary) reference code
Here FILE is a predefined structure, defined in “stdio.h” file. This structure holds extra information about
file-name, open-mode, file-type(binary/text), buffer-size(block-size), pointer to file data, pointer to current
read/write byte, etc. This FILE structure is used for file streaming as said above.
The fopen() function first creates a memory for FILE structure and file-data-buffer (follows dynamic memory
allocation system), later loads file contents from disk to this memory. Finally returns this FILE structure
address (as shown above). If unable to open a file then it returns NULL.
C-Family 271 Data Files
Closing a file: The function 'fclose()' closes an already opened file. After completion of our task on file,
it must be closed. This operation involves in updating file contents on disk (saving back to disk) and also
releases buffer & FILE structure’s space in the RAM. The syntax is
int fclose(FILE *filePointer); // It returns zero, if successfully closed a file, otherwise returns -1.
20 30 40 45 56 23 34 0 ⤶ 20 30 40 45 56 23 34
#include<stdio.h>
void main()
{ FILE *fp; // pointer to file
int n;
fp=fopen("[Link]", "wt"); // w=write mode, t=text file.
if( fp==NULL )
{ printf("file not opened"); return;
}
while(1)
{ printf(“ enter a value :”);
scanf(“%d“ , &n);
if( n==0) break;
fprintf( fp , “%d\n“, n ); // writes ‘n‘ to file
}
fclose( fp ); // saving file contents on disk
}
fread() syntax: fread( &varaible, sizeof( variable), [Link] variable items, file-pointer )
&variable this gives address of variable where the data to be inserted
sizeof(variable) this gives size of data to be read from a given file.
[Link] variable items in case array of items exist.
file-pointer refers pointer to file.
C-Family 274 Data Files
Copying one file content to another file (file can be binary or text)
Note: the binary file organization works for both text/binary format files
this program reads byte by byte from source file and writes to target file, to store byte values, the suitable
data type is char.
void main()
{ FILE *fs, *ft; char ch;
char sName[30], dName[30];
printf(“enter source & destination file names :”);
gets(sName); gets(dName);
fs=fopen( sName , ”rb”);
ft=fopen( dName , ”wb”);
if( fs==NULL || ft==NULL) { printf(“files not opened”); return; }
while(1)
{ k=fread( &ch, sizeof(ch), 1, fs );
if(k<=0) break;
fwrite( &ch, sizeof(ch), 1, ft );
}
fclose(fs); fclose(ft);
}
C-Family 275 Data Files
EOF: it is a macro, represents end of file mark for the text files. (EOF value is equal to 26)
feof(): It is used to check whether a given file has reached the End Of File mark or not.
rename():changes the name of an existing file. syntax: rename(“oldName”, “newName”);
remove():deletes a file from disk. syntax: remove(“fileName”);
filelength(): it gives length of file (the number of bytes occupied by the file)
Input: Output:
hello ⤶ File name: “[Link]”
how are you ⤶ hello
how do you do ⤶ how are you
fine ⤶ how do you do
thanks ⤶ fine
^Z (press f6) (^Z is equal to EOF thanks
total=(st.m1+st.m2);
avg=total/40;
if( st.m1<35 || st.m2<35 )
result="Failed";
else if(avg>=60)
result="First class";
else if(avg>=50)
result="Second class";
else result="Third class";
printf("\n %-6d %-20s %5d %5d %-20s", [Link], [Link], st.m1, st.m2, result);
}
fclose(fp);
}
FILE *fp;
fp=fopen("[Link]","rb+");
if(fp==NULL)
{ printf("\nfile not found ");
exit(0);
}
printf("\n enter employee number:");
scanf("%d",&eno);
while(1)
{ k=fread(&e,sizeof(e),1,fp);
if(k==0) break;
if(eno==[Link])
{ found=1; // record is found
break;
}
}
if(found==0) { printf("\n Record not found"); return; }
pos=ftell(fp); // this function returns the current position of read/write pointer
pos=pos-sizeof(e);
fseek(fp, pos, SEEK_SET); // move the file pointer one position back
// after reading our search record , the file pointer moves to next-record, so to replace our record data, we have to move
// the file pointer back. The above code moves like that.
printf("old salary : %.2f", [Link]);
printf("enter new salary:");
scanf("%f", &[Link]);
fwrite(&e,sizeof(e), 1 ,fp); // overwriting old record
fclose(fp);
printf("\n address suceessfully modified");
}
// --------------------------------------------------------------------------------------------------------------------------------------
// print function, prints all records
void print()
{ EMP e; int k, count=0;
FILE *fp;
fp=fopen("[Link]", "rb");
if(fp==NULL)
{ printf("\nfile not found ");
return;
}
while(1)
{ k=fread(&e,sizeof(e), 1,fp);
if(k==0) break;
printf("\n employee number: %d",[Link]);
printf("\n employee name : %s",[Link]);
printf("\n Salary: %.2f", [Link]);
count++;
printf("\n--------------------------------");
}
printf("\n(%d) records found", count);
fclose(fp);
}
This book softcopy is available in [Link] website, to download the file, search through keyword ‘cfamily’.
This pdf file(s) designed for 2-sided print-copy (Xerox hard copy).