4. This work is licensed under the Creative Commons Attribution-NonCommercial-
ShareAlike 3.0 Unported License. To view a copy of this license,
visit http://creativecommons.org/licenses/by-nc-sa/3.0/
or send a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain
View, California, 94041, USA.
The design and artwork on the cover page of this book was done by Mr. Vishnu
Sivadas, and the artwork from openclipart.org was used. www.openclipart.org.
This book has been typeset in LATEX
You are free to share, copy or distribute this book
6. Dedicated to my Parents
&
My dear friends of GECB
EEE(2008-2012)
A Tribute to
Dennis M. Ritchie
(1941-2011)
14. Preface
Programming can be a nightmare for many, the reason is that they don’t have
an understanding of what they are handling. Programming can be made in-
teresting and fun. It is actually even more interesting and easy than all other
sciences because all we need to do an experiment with a programming language
is the computer and software. Thanks to the free software movement, almost
all program compilers and IDEs are available as free software. I do not claim
this book to be a masterpiece compared to many other books that are avail-
able today, but I do know that it will help someone someday. I hope this book
will be of help to at least some of the readers. I’m open to all criticisms and
appreciations.
I wrote this book using free software tools—Open Office Writer, Open Office
Draw, Gimp and LATEX. All the example programs have been tested using gcc-
4.4.5. This book is being released under the Creative Commons License.
I would like to express my gratitude to Mr. Vishnu Sivadas for his sincere
effort in designing the cover page, proof reading the book and typesetting it.
Finally I request the readers to pardon me for any errors that might have
crawled in irrespective of all efforts to avoid them. You can contact me at
vineeth.kartha@gmail.com.
Vineeth Kartha
xiii
16. Chapter 1
Introduction
“Let us change our traditional attitude to the construction of programs: Instead
of imagining that our main task is to instruct a computer what to do, let us
concentrate rather on explaining to human beings what we want a computer to
do.”
Donald E. Knuth
Almost everyone has his own notion about programming. For most of the
beginners programming is a herculean task which is accomplished only by geeks
and they look at and approach the programming languages with such an idea
and as a result they fail to enjoy it.
Before we start we should have a clear answer to two basic questions.
1. What is programming?
2. What is software?
Let’s answer the first question. We spent a lot of money and time in buying
our computers. We take care in choosing the processor, the accessories, the
memory capacity and all other such aspects, but despite all this our computers
are the stupidest things in the world. We have to tell it very precisely what,
when and how to do things, our computers cannot think. The only advantage is
that it acts fast and it is a very obedient slave. So it will do exactly (it will even
destroy itself if your command says so). So the process of telling our computers
what to do is called programming.
Programming is also explained as the breaking of a task into small steps.
Programming is actually a step by step approach in solving a larger problem.
Suppose we are given the task to sort out students in a class according to their
marks, we look for the top mark first and we proceed so on till we have sorted
out each student, this is programming, our brain has been programmed through
our experiences and we act accordingly.
Unfortunately our computers aren’t smart enough. So we have to tell it.
The second question, what is software?
Most often the answer will be, a program executed on the computer!
A program is merely a set of instructions that a computer executes. Software
is much more than that.
Software is the collection of
1. Instructions that we call as programs
1
17. 2 1. Introduction
2. Data structures that we used to handle data in the program
3. Documentation that includes all hard copy and soft copies that describes
the use and operation of the program
Today all software can be classified in 7 domains:
1. System Software: A collections of programs written to service other
programs, some process deterministic data (text editors, compilers etc.),
others process indeterministic data (OS, drivers etc.). It is characterized
by heavy interaction with hardware. It requires principles of scheduling,
resource sharing, memory management, complex data structures etc.
2. Application Software: Stand alone programs that solve a specific busi-
ness need. Applications in this area process business or technical data in a
way that facilitates business operation or management/technical decision
making used to control business in real time.
3. Engineering/Scientific Software: These are tools that help engineers
to analyse and interpret data obtained from experiments.
4. Embedded Software: This is a software that resides within a product
or system and is used to implement and control feature and function for
end user.
5. Product-line Software: Designed to provide specific capability for use
by many different customers.
6. Web Applications: These are network centric software, category spans
a wide array of applications found on the internet today.
7. Artificial Intelligence: Makes non-numerical algorithms to solve com-
plex problems that are not amenable to computation or straight forward
analysis. Applications within this area include robotics, expert system,
pattern recognition, artificial neural networks, game playing etc.
Now, as we are clear about what programming and software is, let’s see how
we can become a good programmer.
To be a good programmer you should be able to think in a simple and unnatural
way. The characteristics of a good programmer are:
a. Logical thinking
b. Patience
c. Perceptive
d. Faces a challenge with joy
Programming is something to have fun, tackle a problem head on and get
involved in it until solved. That will make you the best programmer. Also try to
learn a few languages through and out, it’s always better to know one language
completely than to know several languages and yet not being able to use all it’s
features.
By now the reader should have some idea about whether programming is
his/her cup of tea. If it is, let’s move on and learn one of the most beautiful
and mostly used programming language, C.
18. 3
In the early days of computer development, there were two levels of program-
ming, the machine level and the assembly level. Programming and debugging
using these two methods was tedious and time consuming. The programmer
had to manage the hardware components himself. He had to consider every
aspect of the hardware before he can write a program.
Later on when computers became more common, another class of languages
called high level languages developed. Fortran, Cobol, Basic, C were all such
high level languages. These languages could be written in the human under-
standable form. These languages made the underlying hardware invisible to the
programmers and made the syntax easier.
It was in the 1970s along with the development of UNIX that the concept
of system programming languages, having attributes of both “low level” and
“high level” languages also developed. System programming languages have the
advantages of high level languages and also help in taking control of underlying
hardware itself.
C was developed as a system programming language by Brian W. Kerning-
han and Dennis M. Ritchie at Bell Labs. Two earlier versions were named A
and B.
Though C was developed for implementing system software, later on it was
used for application software and soon C became a general purpose language. C
can be used in many places where assembly language played major role. Today
even microcontroller programming is done in C.
The first version which is known as K & R C (named after it’s inventors)
remained a standard till 1983 when “The American National Standards Insti-
tute” formed a committee to establish a standard specification of C. In 1989,
the standard was ratified as ANSI X3. 159-1989 “Programming Language C”.
This version of the language is often known as ANSI C, Standard C or some-
times C89. In 1990 ANSI C was adopted by ISO as ISO/IEC 9899:1990 which
is called C90. In the late 1990s again revision was made incorporating inline
functions, data types like long long int and complex to represent complex
numbers, variable length arrays and also support for one line comment.
C has directly and indirectly influenced many of the major languages avail-
able today. So learning C can make you master of almost all programming
languages. The concepts are almost the same.
References
1. “The C Programming Language”, K & R.
2. “Development of C Language”, Dennis M. Ritchie.
3. “Software Engineering: A Practitioner’s Approach”, Roger S. Pressman.
19. Chapter 2
Basic Concepts
Let us look into detail a few points mentioned in the previous chapter. We
learned that a program can be written in machine language which is nothing
but just 1s and 0s, assembly language where we use shorter words but still
lengthy steps to do even the simplest task.
For both these two methods the programmer should thoroughly know the
architecture1
of the microprocessor they are programming on. These programs
will be platform dependent, i.e., a program written for the Intel Pentium IV
processor will not work on a Core 2 Duo or the latest i7 processors.
Then we have the high level programming which is much easier to learn and
practice and it helps in making faster, platform dependent programs. Let us
look at a simple statement to add 2 numbers.
In most high level languages we will write
c = a+b;
where result of a+b is stored in c.
This is quite well understood even by a person who doesn’t know programming.
Now let’s look at the assembly code for an Intel 8085 processor.
MVI A, value
ADD B
The statements are almost understood (ADD B tells us that we are adding
value in B). But we don’t really understand what is being added. Here one of
the number should be in the accumulator and the value in register B should
be added to it. This might seem confusing to those who are new to assembly
programming and this itself is the disadvantage of assembly programming.
The machine code will contain a series of 1s and 0s which is not possible to
by-heart and so we see how high level languages made programming easy.
But there is a catch in that, machines understand only machine code, and,
this is the lowest level at which a program can be written as it is directly
understood by the machine. But we have just seen the practical difficulties
associated with it.
1It is the conceptual design and fundamental operational structure of a computer system,
it’s a functional description of requirements and design implementation for various parts of a
computer.
4
20. 2.1 Assembler 5
Both assembly language and high level language programs need to be con-
verted to machine code before they can be executed.
2.1 Assembler
A utility program called assembler translates the assembly language codes to
machine code. It creates an object code as it’s output which can be executed
by the machine. The object code generated will be specific to each micropro-
cessor, or microcontroller. There are various assemblers like TASM, NASM etc.
Though studying assembly language is difficult, learning it gets you more closer
to your hardware. And also C is a system level programming language and so
C has several features to include assembly programs of which we will see later
on.
When we deal with translation of high level languages to machine code, we
come across two terms, compiled and interpreted languages.
2.2 Compilers and Compiled Language
Compilers itself are programs that transform a program in high level language
to an executable program. C is defined to be a compiled language that means
the source code is given to a compiler which converts it to the executable form.
Early compilers were written in assembly language. Some compilers gener-
ate an object code (executable file) that can run on various platforms. Such a
compiler is called cross-compiler. Later on compilers were written in the respec-
tive languages itself. It was called self hosting compiling and was first created
for LISP at MIT in 1962. But then arouse the ‘chicken & egg problem’. How
can we have a chicken without an egg and how can we have an egg without a
chicken?
Suppose we have written a compiler for language X in X itself then how will
we compile it first? Most often an interpreter or compiler written in Y is used
first. This method is called bootstrapping.
The advantages of bootstrapping are
1. It’s a non-trivial test of language being compiled.
2. Compiler developers need to know only that particular language.
2.3 Structure of a Compiler
A compiler consists of
→ Front End: Where it checks the language semantics, displays errors and
generates the IR (Intermediate Representation).
→ Middle End: Here code is optimized, useless code is removed and con-
stants are identified and propagated.
→ Back End: Here finally the IR is converted to assembly code.
21. 6 2. Basic Concepts
2.4 Interpreters
These are also programs used to convert source code to object code.
It may be a program
1. that executes instructions directly
2. translates source code into some efficient intermediate representation and
immediately executes this
3. expilcitly executes stored precompiled code made by a compiler
The most commonly used compilers for C are CC (C Compiler) and GCC
(GNU Compiler Collection).
These two are used in Unix and Linux operating systems.
∗ mingw32 is an extension to GCC that does cross compilation.
∗ TURBO C is a compiler for Windows.
TURBO C is not only a compiler but an Integrated Development Envi-
ronment.
Now let’s move on to the language itself. We will first have a look at the
basic program.
#include <stdio.h>
int main ()
{
printf("Hello World"); // Prints Hello World
return 0;
}
The first line of the program, the #include is called the preprocessor and
stdio.h is called header file. Header files are files that contain some predefined
functions, in our program the printf() is used to print a text Hello World
on the screen and this function is defined in the header file stdio.h. A header
file is different from a library file and most often people confuse them. Header
files merely contain declaration of functions but the library functions contain
the actual implementation of the functions. Library files are binary files.
∗ Another feature of the C program is the function main(). Anything that
has to be executed should lie in the main().
∗ Each and every instruction in the program is called statements and state-
ments should terminate with a semicolon (;).
∗ You might have noticed a sentence starting with //. This is called com-
ments. Comments are used for easy understanding of the code and for
writing explanations on the code. A commented part will not be executed
by the compiler, so this feature can be used to deactivate a certain part
of the code than deleting it.
Comments are of two types,
a. Single line: It starts with //(two forward slashes), and it should lie
in one line.
b. Multi-line: It starts with /* followed by multiple lines of comments
and it should be terminated by */.
22. 2.4 Interpreters 7
∗ The statements in main() are one block of statements as such.
It should be contained within opening and closing braces {}.
∗ And finally we have the return 0; statement. This statement tells the
compiler that on end of the program the number zero should be returned
to the operating system by the main().
These return statements are quite useful in proper termination of programs
especially when a program crashes. This statement will be explained in
detail in the chapter on functions.
Now we have seen some common features of a C program. We have just
scratched the surface of a vast topic. We will see in detail all these concepts in
the coming chapters.
The life cycle of a program is shown in Figure 2.1.
Figure 2.1: Life Cycle of a Program
Now we will see how to convert our Hello World program to an executable.
Open notepad and save the above program as hello.c. Then open the
‘Terminal’ in ‘Applications’ and type
cc hello.c
Make sure you were in the same folder as the hello.c file.
Now type
./a.out
You should see Hello World on your screen or else check the error messages
and check your program. a.out is the output file generated.
In a TURBO C compiler, on the menu bar there will be compile command
and a run command. Another point for TURBO C users is that the output
screen will not be visible because the program executed and terminated. So to
hold the output for some time, before the return 0; insert a getch();, now
the screen will wait till a key on keyboard is pressed.
Again for cc and gcc we can name the output file by any name we want.
For that compile as follows
gcc -o name file.c
Now to execute you type
./name
The switch -o means output. There are several more switches, see appendix for
more details on GCC.
23. 8 2. Basic Concepts
Now the reader must have had an idea about the basic requirements and
procedures in making a program.
2.5 Exercise
1. Write a short note on the life cycle of a program.
2. Write a brief note on C programming.
3. Write short notes on compiled and interpreted languages with example.
4. Write advantages of interpreted languages.
5. What is bootstrapping?
References
1. “Microprocessor and its Applications”, B. Ram.
2. “Microprocessor and its Applications”, Gaonkar.
3. K & R C.
4. “C Programming in Unix”, John Vally.
24. Chapter 3
Identifiers and Data Types
3.1 Identifiers
Throughout our program we will have to use variables to store different types
of data. Variables are like containers that contain a value assigned to it, we can
use this variable name instead of that particular value throughout the program
depending on it’s visibility1
.
There are certain rules to be remembered while naming variables:
∙ The name should start with an alphabet.
∙ The name should not be any reserved keywords like int, float, volatile
etc.
∙ The names are case sensitive. AVG and avg are different variables.
∙ The name should not contain special characters like $, #, ! but it can
contain (underscores).
∙ The name can contain alphabets from a–z, A–Z and 0–9.
∙ The name should not start with a number.
∙ The name should not contain spaces.
∙ The name can start with an underscore but usually such variables are used
by the system. So it is better to avoid such a situation.
When naming a variable it is always advisable to
∙ Name the variable depending on what it represents.
∙ Keep them as short as you can but they should be understandable about
what they represent.
3.1.1 Keywords in C
Table 3.1 shows the list of keywords in C.
1A variable can be made available throughout the program or only in a particular part of
the code. We will discuss in detail about this in the coming chapters.
9
25. 10 3. Identifiers and Data Types
auto break case char const continue default do
double else enum extern float for goto if
int long register return short signed sizeof static
struct switch typedef union unsigned void volatile while
Table 3.1: List of keywords
3.2 Data Types
Data types in C can be classified as shown in Figure 3.1 below.
Figure 3.1: Data types
3.3 The Basic Data Types
3.3.1 Integer
An integer is a numeric item that can contain a positive or negative whole
number.
int varname;
We can also declare many variables in a single line and even initialize their
values.
int var1 , var2 , var3 =5;
When an integer data type is declared the compiler allocates 2 or 4 bytes of
space, depending on the operating system. The Unix and Linux environments
26. 3.3 The Basic Data Types 11
provide a 4 byte memory whereas it is 2 bytes long in the MS-DOS environment.
Type modifiers can be used to get a desired size irrespective of the OS. Usually
an integer can contain a value between −32, 768 to 32,767. We can use the type
modifier unsigned to limit the range to only the positive side. The following
table shows the size and limit of the int data type with different type modifiers.
Declared Length in bytes Value Range
int 2 or 4 At least −32, 768 to 32,767
long int 4 −2, 147, 483, 647 to 2,147,483,648
short int 2 −32, 768 to 32,767
unsigned int 2 or 4 At least 0 to 65,535
unsigned short 2 0 to 65,535
unsigned long 4 0 to 4,294,967,295
Table 3.2: int data type
3.3.2 Floating Point
A floating point is a class of numeric variables that allow the storage of fractions
and exponents to very precise values. A floating point number has a sign, an
integer part and a fractional or exponential part.
float var1 , var2 =1.2;
E.g. 3.2435𝐸 + 03 is the same as 3243.5
Normally floating point number are 4 bytes long, the data type double can
be used to make an 8 byte long floating point number. The floating point
numbers can be set with the precision of how many digits to be displayed after
the decimal point.
Declared Length in bytes Limits of positive values
float 4 8.43𝐸 − 37 to 3.37𝐸 + 38
double 8 2.225074𝐸 − 308 to 1.797693𝐸 + 308
long double 10 2.225074𝐸 − 308 to 1.797693𝐸 + 308
Table 3.3: float data type
The float data type allows signed values, so using unsigned along with
float or double will cause a compiler error.
3.3.3 Character
A character is a single byte containing any character in ASCII code. It can be
alphabets, numbers2
, special characters, newline, form feed etc. A char data
type occupies one byte of memory. They are stored in their ASCII form.
char a, b=‘c’, c=‘1’;
2We can represent numbers with the char data type but we cannot treat them as numbers
and cannot be used for calculations.
27. 12 3. Identifiers and Data Types
A character string can be declared only as an array.
char a[10];
These data types can be further modified using the data type modifiers and
storage class specifiers.
3.4 The Data Type Specifiers
3.4.1 signed or unsigned
unsigned data items are used for positive values. But signed data items can
have values ranging from a minimum negative value to a maximum positive
value.
3.4.2 long or short
The short type is used for saving memory. It has half length of long type.
3.4.3 const
The keyword const is used along with a variable name to make it a constant.
Throughout the scope of the variable it’s value will remain a constant and any
attempt to modify the value during runtime will result in an error.
3.4.4 volatile
When a variable is declared as volatile, we are telling the compiler that the
value of the variable might be changed at any time—without any action being
taken by the code the compiler finds nearby.
3.5 The Storage Class
The storage class specifier specifies the segments of the program where the
variable is recognized, and how long the storage of the value of variable will
last. The storage class specifiers are:
3.5.1 Automatic variables (auto)
This is the storage class that a compiler uses by default. A variable declared
with auto as the storage specifier is stored in the memory and it is local to the
function in which it is declared. Auto variables declared in different functions
even though having the same name are independent. The life cycle of such
variables are till the function which contains them are executed.
auto int a;
28. 3.6 User Defined Data Types 13
3.5.2 Static variables (static)
These variable contain the value zero by default when created or we can say
that they are initialized with zero, unless we give a value. These variables are
local to the function but they exist till termination of the program. So the value
of the static variable unlike the auto variable is not lost once the function is
over, it exists till the end of the program. And so if the function is called for a
second time somewhere else in the program then the variable uses the previously
stored value. Such variables can be used as counters.
static int a;
3.5.3 External variables (extern)
The scope of such variables are global, i.e., they are available all over the pro-
gram. Sometimes a single program may contain several files linked, a variable
with storage specifier extern is available everywhere. So it is accessible by all
the functions in the program. If a function contains a local variable with the
same name as an extern variable then in the function preference will go first
to the local variable. This is a point to be kept in mind.
extern int a;
3.5.4 Register variables (register)
Register variables are similar to auto variables, the only difference is that the
auto variables are stored in the memory whereas the register variables are stored
in the registers of the CPU. We use the register variables because the CPU
registers respond much faster than the memory. Register variables maybe of 2
or 4 bytes and so most suitable for integer and character data types, also the
CPU registers are needed for other processes of the system so they should be
used only when necessary. We should not use too many register variables.
register int a;
3.6 User Defined Data Types
3.6.1 Arrays
Arrays are a collection of the same data type. There are one-dimensional and
multi-dimensional arrays in C. Eg. a character array can be used to store a
word, sentence or even a paragraph depending upon the size of the array.
int num [20];
This is an array with space for 20 integers. The first element of an array is
located at num[0], the next one at num[1] and so on. The last element is at
num[19]. In general, an array of size 𝑛 has first element at arrayname[0] and
last element at arrayname[n-1]. We can create arrays for any data type, even
29. 14 3. Identifiers and Data Types
for the user defined data types that we will see shortly. A multi-dimensional
array can be considered as an array of arrays. We can represent a matrix as a
two-dimensional array. For a character array of size 𝑛, we can store only 𝑛 − 2
characters because the last ((𝑛−1)𝑡ℎ
) position is occupied by the null character
0 which represents the termination of the string.
3.6.2 Structure
An array can contain only values of same data type. Suppose we want to group
the details of a student like roll number, name, marks, rank etc., we have to
create a structure. A structure can be considered as a group of different data
types. We will study in detail about structures and unions in a later chapter.
3.6.3 Union
Union is similar to structure . The only difference is that a structure occupies
a memory equivalent to the sum of lengths of all elements present in it whereas
the size of a union is equal to the size of the largest element present in it.
3.6.4 Enumerations
Enumerations are nothing but just assigning names to numbers.
enum{sun ,mon ,tue ,wed ,thur ,fri ,sat}
With the above declaration we can use sun to represent 0, mon to represent
1 and so on. We can also change the values.
enum{sun=1,mon ,tue ,wed ,thur ,fri ,sat}
Then the numbering starts from 1 and goes on increasing by 1.
3.6.5 Typedef
Typedef cannot be considered as a pure data type because all it does is to
rename an existing data type to a new one. Eg.
typedef int number;
typedef char name [10];
Now we can use number as keyword to declare integer data types and name
to declare character arrays of size 10.
3.6.6 Typecasting
Typecasting is making a variable of one type, such as a float, act like another
type, an int, for one single operation. To typecast something, simply put the
type of variable you want the actual variable to act as inside parantheses in
front of the actual variable. (char)a will make ‘a’ function as a char.
30. 3.7 Exercise 15
There is explicit and implicit typecasting. In implicit typecasting (type
conversion) the compiler converts one data type to another where ever needed.
In explicit typecasting we have to tell the compiler to typecast a variable.
int a=10;
float b=2.5,c;
(char) a; // explicit
c=a/b; // here a is implicitly converted to float
3.7 Exercise
1. Identify which of the variable names are illegal and explain the reason.
(a) $num
(b) 12phone
(c) avg2
(d) date-of-birth
(e) time
(f) my,file
(g) break
(h) default
2. What are data types? How can they be classified?
3. char is often treated as an integer type. Why is it so?
4. What are the advantages and disadvantages of floating point numbers over
integers?
5. Differentiate between a structure and an array.
31. Chapter 4
Input/Output Operations
Most earlier programming languages had poor support for I/O. The designers of
C overcame this problem by having I/O operations done using library functions,
so that program designers can have tailored I/O. As C has evolved, a library
package known as the ‘Standard I/O Library’ or stdio, has evolved with it and
has proved to be both flexible and portable. This package has now become part
of the Standard.
In C everything is treated as a stream of bytes, whether it is a file or the
standard input or output. The file I/O has been reserved for a later chapter.
Now let’s see the basic Standard I/O.
printf() is the command that tells the compiler to print something on the
screen, and scanf() is the command that tells the compiler to read something
from the standard input device.
The functions can be illustrated with the following program:
/*
A program to explain the STANDARD I/O
*/
#include <stdio.h>
int main ()
{
int num;
char alph;
float x;
printf("Enter an integer , a character and a
floating point num: ");
scanf("%d,%c,%f" ,&num ,&alph ,&x);
printf("The integer is %d nThe character is %c
nThe floating point num is %f n",num ,alph ,x);
return 0;
}
Program 4.1: Standard I/O
You can compile the above program and check it’s output.
In the above program you can see a lot of weird characters like %d, &num etc.
The %d %f etc. are called conversion characters. The table below provides the
list of conversion characters.
The conversion characters can also be used to set the precision of the floating
16
32. 4.1 The gets() and puts() 17
Conversion character Displays argument (variable’s contents) as
%c Single character
%d Signed decimal integer (int)
%e Signed floating point value in E notation
%f Signed floating point value (float)
%g Signed value in %e or %f format, whichever is
shorter
%i Signed decimal integer (int)
%o Unsigned octal (base 8) integer (int)
%s String of text
%u Unsigned decimal integer (int)
%x Unsigned hexadecimal (base 16) integer (int)
Table 4.1: Conversion Characters
point numbers. %0.2f gives a precision of up to 2 decimal places. The general
format is %x.yf, where x and y are numbers to denote the length.
Then there are escape sequences which help in formatting the output by
providing newline, tab etc. Table 4.2 provides the list of escape sequences in C.
Sequence Meaning
a Beeps the speaker
b Backspace (moves the cursor back, no erase)
f Form feed (ejects printer page; may clear the screen on
some computers)
n Newline, like pressing the Enter key
r Carriage return (moves the cursor to the beginning of
the line)
t Tab
v Vertical tab (moves the cursor down a line)
The backslash character
’ The apostrophe
" The double-quote character
? The question mark
0 The “null” byte (that’s 0, not the letter O)
Onn A character value in octal (base 8)
xnnn A character value in hexadecimal (base 16)
Table 4.2: Escape Sequences
The printf() and scanf() are functions defined in stdio.h. We can also
input to and get output from a file. File I/O is a topic for a further chapter but
the reader should know from the beginning itself that the C compiler treats all
input and output devices and files as streams of bytes.
4.1 The gets() and puts()
The scanf() has a problem when handling strings, it will read only till the
blank space. It will not read after a blank space occurs so we can give as input
only a word. gets() and puts() are functions in the stdio.h header file. The
gets() is used for input and puts() is used for output of a string.
#include <stdio.h>
int main ()
33. 18 4. Input/Output Operations
{
char msg [50];
printf("nEnter the message: ");
gets(msg);
printf("nThe message ist: ");
puts(msg);
printf("The message can also be printed:
%sn",msg);
return 0;
}
Program 4.2: gets() and puts()
4.2 Exercise
1. Write a program that accepts your name, age and occupation and prints
them as below.
Name : Vineeth
Age : 20
Occupation : Student
2. Write a program that prints the value of 𝜋(22/7) up to 4 decimal places.
(Hint: use %0.4f as conversion character)
34. Chapter 5
Operators
Every program will contain expressions. Expressions are a combination of op-
erators and operands. Eg. the + operator requires two operands and it acts on
the operands and produces the sum as the result.
In C the operators can be classified based on the number of operands it
operates on as:
1. Unary operators
2. Binary operators
3. Ternary operators
They are also classified based on type of operation as:
1. Arithmetic operators
2. Relational operators
3. Logical operators
4. Assignment operators
5. Increment and Decrement operators
6. Bitwise operators
7. Conditional operators
5.1 Binary Operators
5.1.1 Arithmetic Operators
All the basic arithmetic operations can be carried out in C. All the operators
have almost the same meaning as in other languages. Both unary and binary
operations are available in C language. Unary operations operate on a single
operand.
The operators are + (addition or unary +), − (subtraction or unary minus),
* (multiplication), / (division), % (modulo or the remainder operator—it gives
remainder of division between 2 numbers1
).
1The modulus operator cannot be applied for floating point numbers, it will be an error.
19
35. 20 5. Operators
Eg. 5%2 = 1
Except the modulus operator all other operators are same for floating point
numbers.
5.1.2 Relational Operators
The relational operators used in C are:
<: less than
>: greater than
<=: less than or equal to
>=: greater than or equal to
==: equal to2
!=: not equal to
These operators always return the values as true or false (0,1).
5.1.3 Logical Operators
The logical operators are:
&&: Logical AND
This operator returns the value true only if both the subordinate expressions
are true.
Eg. (x>2) && (y<4)
||: Logical OR
This operator returns the value true if at least one of the subordinate expres-
sions is true. If the left term is true then right term is not evaluated at all.
Eg. (x>2) || (y<4)
!: Logical NOT
5.1.4 Assignment Operators
The = is the assignment operator used to assign values to variables. The variable
to which the value is to be stored should come on the left side and the value or
variable whose value is to be stored comes on the right side.
count = count + 1 can be written as count+=1. Similarly we can write
count-=5 for count = count - 5.
For multiplication, division and modulus also we can apply this rule.
5.1.5 Bitwise Operators
Normally we don’t have to use these operators. We only need to handle data in
bytes. But for programs like encryption, data compression etc. we will have to
handle data at the bit level.
Bitwise AND (&)
& operator is bitwise AND. The following is a chart that defines &, defining
AND on individual bits.
2Not to be confused with ‘=’ which is an assignment operator and not a comparison
operator
36. 5.1 Binary Operators 21
x y x&y
0 0 0
0 1 0
1 0 0
1 1 1
Table 5.1: Bitwise AND
Bitwise OR (∣)
The ∣ operator is bitwise OR (it’s a single vertical bar). The following is a chart
that defines ∣, defining OR on individual bits.
x y x∣y
0 0 0
0 1 1
1 0 1
1 1 1
Table 5.2: Bitwise OR
Bitwise XOR
The ˆ operator is bitwise XOR. The usual bitwise OR operator is inclusive OR.
XOR is true only if exactly one of the two bits is true. The XOR operation is
quite interesting, but we defer talking about the interesting things you can do
with XOR until the next set of notes.
The following is a chart that defines ˆ, defining XOR on individual bits.
x y x ˆ y
0 0 0
0 1 1
1 0 1
1 1 0
Table 5.3: Bitwise XOR
Bitwise NOT
There’s only one unary bitwise operator, and that’s bitwise NOT. Bitwise NOT
flips all of the bits. There’s not that much to say about it, other than it’s not
the same operation as unary minus. The following is a chart that defines ˜,
Bitwise Shifts
There are two bitwise shift operators, namely shift left and shift right. They
are represented by the << and >> operators, respectively. These operations are
very simple, and do exactly what they say: shift bits to the left or to the right.
The syntax for a shift operation is as follows:
[integer] [operator] [number of places];
A statement of this form shifts the bits in [integer] by the number of
places indicated, in the direction specified by the operator. Probably the best
37. 22 5. Operators
x ˜ x
0 1
1 0
Table 5.4: Bitwise NOT
way to visualize this is with an example. Take a look at the following code,
which demonstrates a shift left.
x = 0000 0110 1001 0011
x = x << 1;
x = 0000 1101 0010 0110
From this example, you should be able to see what’s going on. Every bit in x is
shifted to the left by one place. When you do this, the MSB (most significant
bit) of x is lost, because there isn’t another place to shift it to. Similarly, after
a shift left, the LSB of x will always be 0. There is no position to the right of
the LSB, and so there’s nothing to shift into the LSB, so it’s assigned a value
of 0.
5.2 Unary Operators
5.2.1 Unary plus and minus
It controls the sign of a numeric constant or variable. The operator is prefixed
to the constant or variable. It can also be used to change the sign of expressions
as a whole.
Eg. −5, +2, −𝑥, −(𝑥 + 𝑦)
5.2.2 Increment and Decrement Operators
The increment ++ and decrement −− operators, as the name suggests, are
used to increment and decrement the value of a variable. These operators can
be used in two forms when used in expressions:
1. Post fix norm: In this form the ++ comes after the variable as var name++
or var name--. In this form the value of the variable is first used in the
expression and then incremented.
2. Prefix norm: In this form the ++ or −− comes before the variable as
++var name or --var name. When used in this form the variable value is
first used in the expression and then incremented later.
The following program illustrates the effect of the above mentioned forms.
#include <stdio.h>
int main ()
{
int num1=3,num2;
num2 = num1 ++; //In the post fix form
printf("Num1 =%d nNum2 =%d n",num1 ,num2);
num2 = ++ num1; //In the prefix form
printf("Num1 =%d nNum2 =%d n",num1 ,num2);
38. 5.3 Ternary Operators 23
}
Program 5.1: Increment and decrement operators
The output will be:
Num1=4
Num2=3
Num1=5
Num2=5
The same rule is applicable to the decrement operator also.
5.3 Ternary Operators
5.3.1 Conditional Operator
The operator (expression1)?(expression2):(expression3) is called the con-
ditional operator. It evaluates expression1 and if the result is true it returns
expression2, if result is false it returns expression3.
(x>y) ?x:y;
The above statement will check if x is greater than y and if so it will return x
or else it will return y.
5.3.2 Precedence and Associativity
Two operator characteristics determine how operands group with operators:
precedence and associativity. Precedence is the priority for grouping different
types of operators with their operands. Associativity is the left-to-right or right-
to-left order for grouping operands to operators that have the same precedence.
An operator’s precedence is meaningful only if other operators with higher or
lower precedence are present. Expressions with higher precedence operators are
evaluated first. The grouping of operands can be forced by using parentheses.
Table 5.5 lists the precedence and associativity of the operators we studied.
5.4 Exercises
1. Define precedence and associativity.
2. How are operators classified in C?
3. What is the output of the following statement: 4 + 5 ∗ 3 − 2%3?
4. Write the output of the following program:
#include <stdio.h>
int main ()
{
int a=0;
printf("n %d n %d n %d n",a,++a,a++);
return 0;
}
Program 5.2: Find the output
39. 24 5. Operators
Operator Description Associativity
() Parentheses (function call) left-to-right
[] Brackets (array subscript)
. Member selection via object name
-> Member selection via pointer
++ -- Postfix increment/decrement
++ -- Prefix increment/decrement right-to-left
+ - Unary plus/minus
! ˜ Logical negation/bitwise complement
(type) Cast (change type)
* Dereference
& Address
sizeof Determine size in bytes
* / % Multiplication/Division/Modulus left-to-right
+ - Addition/Subtraction left-to-right
<< >> Bitwise shift left/Bitwise shift right left-to-right
< <= Relational less than/less than or equal to left-to-right
> >= Relational greater than/greater than or equal to
== != Relational is equal to/is not equal to left-to-right
& Bitwise AND left-to-right
ˆ Bitwise exclusive OR left-to-right
| Bitwise inclusive OR left-to-right
&& Logical AND left-to-right
|| Logical OR left-to-right
?: Ternary conditional right-to-left
= Assignment right-to-left
+= -= Addition/Subtraction assignment
*= /= Multiplication/Division assignment
%= &= Modulus/Bitwise AND assignment
ˆ= |= Bitwise exclusive/inclusive OR assignment
<<= >>= Bitwise shift left/right assignment
, Comma (separate expressions) left-to-right
Table 5.5: Precedence and Associativity
40. Chapter 6
Control Statements
A program consists of a number of statements which are usually executed in
sequence. Programs can be much more powerful if we can control the order in
which statements are run. Decision making is one of the crucial and essential
part of a program. We will encounter situations where we will have to make
a decision on how to proceed further. Decision making statements in C check
whether a given statement is true or false. The decision making statements in
C are if else and switch case.
6.1 if...else
The if statement has two forms:
if(expression) statement
if(expression)
{
statements ...
}
else
{
statements ...
}
The statements in the if block are executed if the expression is true and
statements in else block are executed if the expression is false. The if else
statements can also be used in the form of if else ladder or as nested if else.
The curly braces are not an essential part of the if statements if there is only a
single statement following it, but it’s always a good practice to use the braces.
// A program to find largest of two numbers
#include <stdio.h>
int main(int argc ,char argv [])
{
int num1 ,num2;
printf("Enter the first number: ");
scanf("%d" ,&num1);
printf("Enter the second number: ");
scanf("%d" ,&num2);
if(num1 >num2) printf("First number is largern");
25
41. 26 6. Control Statements
else
printf("Second number is largern");
return 0;
}
Program 6.1: Largest of two numbers
6.1.1 Nested if else
if(expression)
{ statements }
else if(expression)
{ statements }
else
{ statements }
The ladder can be extended as long as required.
if (result >= 75)
printf(‘‘Passed: Grade An’’);
else if (result >=60)
printf(‘‘Passed: Grade Bn’’);
else if (result >=45)
printf(‘‘Passed: Grade Cn’’);
else
printf(‘‘Failedn’’);
Nesting can be done in the else tag also.
6.2 switch case
This is another form of the multi way decision. It can only be used in certain
cases where:
∙ Only one variable is tested, all branches must depend on the value of that
variable. The variable must be an integral type. (int or char).
∙ Each possible value of the variable can control a single branch. A final,
catch all, default branch may optionally be used to trap all unspecified
cases.
It’s syntax is
switch(choice)
{
case val1: statements; break;
case val2: statements; break;
default: statement; break;
}
Each interesting case is listed with a corresponding action. The break state-
ment prevents any further statements from being executed by leaving the switch.
Both if and switch constructs allow the programmer to make a selection
from a number of possible actions.
Let us see an example program.
42. 6.3 Conditional Operator 27
// A program to display the day corresponding to a
number
#include <stdio.h>
int main(int argc ,char argv [])
{
int num;
printf("Enter a number: ");
scanf("%d" ,&num);
switch(num)
{
case 1: printf("nSunday n");
break;
case 2: printf("nMonday n");
break;
case 3: printf("nTuesday n");
break;
case 4: printf("nWednesday n");
break;
case 5: printf("nThursday n");
break;
case 6: printf("nFriday n");
break;
case 7: printf("nSaturday n");
break;
default: printf("Error");
break;
}
return 0;
}
Program 6.2: switch case
6.3 Conditional Operator
The conditional operator is similar to if else but nesting is not possible.
condition?statement1:statement2;
Here we check for the validity of the condition. If it’s true statement1 is
executed or else statement2 is executed.
6.4 Loops
The other main type of control statement is the loop1
. Loops allow a statement,
or a block of statements, to be repeated. Computers are very good at repeating
simple tasks many times, the loop is C’s way of achieving this. A looping
statement consists of an initializing statement, a validation statement and an
increment/decrement statement. There are two types of loops in C they are:
∙ Entry controlled loops
∙ Exit controlled loops
1Loops are also called iteration statements.
43. 28 6. Control Statements
6.4.1 Entry Controlled Loops
Entry controlled loops are loops in which the expression is checked before the
loop is executed. Such loops are used when we have to execute loop only if
the validation expression is valid. The entry controlled loops in C are for and
while.
The for Loop
The syntax of for loop is
for(initializing statement; validation expression; increment/decrement)
{ loop body }
Basically a for loop can be written as simply as
for( ; ; )
{ loop body }
It’s only the semicolons within the parentheses that are important in a for loop.
The above loop will be executed infinitely and is called an infinite loop.
// A program to print first 10 natural numbers
#include <stdio.h>
int main(int argc ,char argv [])
{
int i=1;
for(i;i <=10;i++)
{
printf("n %d n",i);
}
return 0;
}
Program 6.3: for loop
For a loop body with a single statement, the { } can be avoided. In the
below program
for(int i=1;i <=10;i++)
{
printf(‘‘n %d n’’,i);
}
can be replaced by
for(int i=1;i <=10;i++)
printf(‘‘n %d n’’,i);
but it is always a good practice to use the braces, it makes the program more
readable and understandable.
The for loop can be used as a nested for loop.
The while Loop
while is another entry controlled loop that checks the validity of an expression
before executing the loop body. Unlike a for loop the while has the incremen-
t/decrement statement within the loop body.
44. 6.4 Loops 29
The syntax of while loop is:
while(expression)
{ loop body }
We can rewrite the program for printing number 1–10 using the while loop.
#include <stdio.h>
int main(int argc ,char argv [])
{
int i;
i=1;
while(i <=10)
{
printf("n %d n",i);
i++;
}
return 0;
}
Program 6.4: while loop
6.4.2 Exit Controlled Loops
Exit controlled loops check the validity of the expression only after each itera-
tion.
The do...while Loop
The do while loop is an exit controlled loop because the expression is checked
for validity only after executing the loop body each time. Such loops are used
when we need the loop to be executed at least once.
The syntax of do while is
do
{ loop body }
while(expression);
The semicolon after while is important in the do while, it marks the end
of the loop.
The program to print numbers 1–10 can be done using do while loop, and
it is left as an exercise for the readers.
6.4.3 The break Statement
Sometimes while executing a loop it becomes desirable to skip a part of the
loop or quit the loop as soon as certain condition occurs, for example consider
searching a particular number in a set of 100 numbers, as soon as the search
number is found it is desirable to terminate the loop. C language permits a
jump from one statement to another within a loop as well as to jump out of
the loop. The break statement allows us to accomplish this task. A break
statement provides an early exit from for, while, do and switch constructs.
A break causes the innermost enclosing loop or switch to be exited immediately.
45. 30 6. Control Statements
The syntax is
break;
6.4.4 The continue Statement
During loop operations it may be necessary to skip a part of the body of the
loop under certain conditions. Like the break statement C supports similar
statement called continue statement. The continue statement causes the loop
to be continued with the next iteration after skipping any statement in between.
The syntax is
continue;
6.5 Exercises
1. Write a program to accept length of 3 sides of a triangle and check if a
triangle can be formed with the given sides.
2. Write a program to calculate the total mark of a student for five subjects
and find out his grade such that if percentage of mark is
I. A => 80
II. B => 70
III. C => 60
IV. D => 50
V. F for failed
Also print the mark list along with student name, roll number, class, year,
percentage and grade in a well formatted manner.
3. Write a program to print the letters of your name in a lower triangular
form.
The name Vineeth should be printed as
V
Vi
Vin
Vine
Vinee
Vineet
Vineeth
4. Write a program to print the Fibonacci series (0,1,1,2,3,5,. . . the next num-
ber is sum of the previous two numbers).
5. Write a program to check if a given number is a prime number.
6. Write a program to generate the mathematical tables up to a given limit.
46. Chapter 7
Structured Data Types
For a large class of problems in computing, it is the data and not the algorithms
that are the most interesting. If the initial design gets it’s data structures
right, the rest of the effort in putting a program together is often quite small.
However, you need help from the language. If there is no support for structured
data types other than arrays, writing programs becomes both less convenient
and also more prone to errors. It is the job of a good language to do more than
just allow you to do something; it must actively help as well.
C offers arrays, structures and unions as it’s contribution to data structuring.
They have proved to be entirely adequate for most users’ needs over the years
and remain essentially unchanged by the Standard.
In this chapter we will discuss the three basic structured data types used in
C.
1. Arrays
2. Structures
3. Unions
There are other structured data types in C like enums and bitfields.
7.1 Arrays
An array is a list of objects all of the same type. The objects comprising an array
are called elements. The dimensions of an array describe how many elements an
array contains and how it’s elements are arranged in memory. Each element is
identified by an index. Giving the relative position of the element within the list,
the first element has the index 0. A one-dimensional array arranges elements
in a linear list whereas a two-dimensional array arranges elements like elements
in a matrix. Arrays of higher dimensions are also possible. The elements of an
array are arranged contiguously in memory. For two and higher dimensional
arrays the elements are stored in row major order (in a matrix X after X[m][n],
X[m][n+1] is stored.).
An array can be for both in-built and user defined data types.
data type arrayname[size ][ size ];
31
47. 32 7. Structured Data Types
Arrays can be initialized only with constant values and not with variables.
The following example shows how to initialize a two-dimensional array.
int sample [2][2]={{1 ,2 ,3} ,{4 ,5 ,6} ,{7 ,8 ,9}};
You can omit the size within the brackets of the last array dimension when you
include an initializer for the array.
7.2 Structures
Arrays allow for a named collection of identical objects. This is suitable for
a number of tasks, but isn’t really very flexible. Most real data objects are
complicated things with an inherent structure that does not fit well on to array
style storage. Let’s use a concrete example.
Imagine we have to collect the data of all students in a college. Each student
will have certain data associated with him like name, class, roll number, marks
etc. So we have to group all these data together as single piece for one student
and repeat the same for all the other students. In such a situation we use
structures. Structures are user defined data types that are a collection of several
other user defined or primary data types. Let’s look at a code snippet
struct student
{
int rollno , marks , avg;
char name [20], class [6];
};
In the above example, student is called the tag or the structure name and
within the braces we’ve declared the variables that the structure student should
hold. Structures do not occupy any memory unless associated with an instance.
The size of a structure is the total size of all the individual elements it contains.
Structure instances cannot be declared without defining the structure.
Once the structure is defined it can be treated just like other data types in
C. We can call it in a function or the main program and access each element of
the structure, we can even create an array with the created structure. Let’s see
a program:
#include <stdio.h>
struct student
{
int rollno ,marks;
char name [20], class [6];
} stud1 ={1 ,450 ,"xyz","ee"},stud2; //A variable can
be declared like this :-)
int main ()
{
struct student s;
// struct student s[10]; An array can also be
declared with student as datatype
printf("Enter the name of the student: ");
scanf("%s" ,&s.name);
48. 7.2 Structures 33
printf("nThe name of the student is: %s
n",s.name);
stud2=s; // Assigning one variable to another
printf("nThe name of the student is: %s
n",stud2.name);
return 0;
}
Program 7.1: Structure
The above example has a lot of treasure in it, let’s dig it all out :-)
∙ We see that right after the definition body of the structure an instance
has been declared, this is one way of declaring instances for the created
structures.
∙ The semicolon that appears right after that is compulsory even if the
instance wasn’t declared. It denotes the end of the structure definition so
missing out the semicolon will result in syntax error.
∙ The instance of the particular structure is defined as a primary data type.
Even an array can be declared and sometimes we use these structures
inside others which we will see soon.
∙ The most important question is, how to access each element of the struc-
ture? The answer is a simple . The . is called a dot operator. It’s syntax
is instance.member name, this will be clear from the above example where
s.name shows how the dot operator functions.
∙ The assignment operator or the = can also be used with structures but
no other operator can be used. We can assign the values of one structure
instance to another instance of the same structure.
∙ The next question is about initializing the instance. The instance de-
clared can be initialized by giving the values of each element within the
{} separated by a comma.
Well that should explain almost the whole of structures. Now there are some
points that I have left out and I have done it intentionally. These are:
∙ What happens if while initialization we input values which are less than
the number of the elements i.e. in the above example student contains 4
elements then what will happen to a statement
struct student a={1,2,‘‘ab’’};
∙ Can we assign only a particular element of one structure variable to an-
other structure variable?
∙ All other questions and possibilities that you can think about have been
left out as an exercise for the reader, after all what thrill is there if you
are provided with all the information. The thrill lies in discovering things
and thats how we c :-)
7.2.1 Nested Structures
Structures can be nested, that is one structure can be used as a data type in
another structure.
49. 34 7. Structured Data Types
struct employee
{
int id ,salary;
char name [20];
}
struct manager
{
struct employee x;
char grpcharge [20];
}
In the above code we can see that the structure employee is nested within
the structure manager because a manager is also an employee with additional
characteristics. So both structures have some common traits. So we can avoid
duplicating of code (some people call it reusability of code).
7.2.2 Unnamed Structures
Structures can also be created without a name, but such structures cannot be
used for later references. We have to create instances of the structure at the
same time when we define the structure.
struct
{
char bookname [10];
int isbn_no;
} book1 , book2 , book3;
With the above code we use the variables book1, book2, book3 but we
cannot write the statement to create a new variable because we do not have a
tag to identify the structure.
7.3 Unions
Unions are user defined data types that are a collection of several other user
defined or primary data types. Does this definition seem familiar! Well it is
because we defined the structures in the same way. So actually then what is
the difference of a union? The difference of a union and a structure lies in it’s
memory allocation. Let’s look at the following code.
struct strdate
{
int year ,dat;
char month [10];
} var1;
union dateunion
{
int year ,dat;
char month [10];
} var2;
In the above example we have declared a union and a structure to hold the
date.
A structure variable var1 will have the memory size of 14 bytes (2 bytes for
year, 2 bytes for dat, 10 bytes for month).
50. 7.4 Exercises 35
But the union instance var2 will have the size of 10 bytes only (the size
required for the largest element). So that’s how a union is different from a
structure. It can accept only the value for one of the elements at a time that
belongs to it. You can picture a union as a chunk of memory that is used to
store variables of different types. Once a new value is assigned to a field, the
existing data is wiped over with the new data.
Unions are used in situations where we need to use only one element of a
structure at a time and thus we can reduce the wastage of space.
The method to access union elements is the same as that for structures.
Now the question is how to initialize an instance of the union. We know that
an instance of a union can hold value to only one of it’s variables.
Let’s see how to do this:
union dob
{
int year ,date;
char month [10];
} var1 ={1990} , var2 ={. date =15};
This is how to initialize a union instance. We can use only one value and
that value will be assigned to the first element. If we are specific about the
element it should be specified as is done for var2 (the . is very important, do
not omit it).
7.4 Exercises
1. Write a program to find the sum of two matrices.
2. Write a program to find product of two matrices (two matrices of order
𝑚 ∗ 𝑛 and 𝑝 ∗ 𝑞 can be multiplied only if 𝑛 = 𝑝).
3. Write a program that will accept an array and then sort elements of the
array in ascending order and display the elements.
4. Write a program that has a structure that contains all details of employees
in a firm. Create structure for a normal employee and for the manager.
And display the details when requested.
5. Write a program to compare two given words (ignore case sensitivity).
51. Chapter 8
Functions
The divide and conquer is the most often used technique in programming large
programs. Programs are divided into smaller modules and finally they are joined
together. This helps in understanding and debugging the code. A function in
C is a block of code that performs a specific task. It has a name and it can
be executed from as many different parts in a program as required. It also
optionally returns a value to the calling program, we have already seen the
main() function.
So function in a C program has some properties discussed below.
∙ Every function has a unique name. This name is used to call function
from anywhere in the code.
∙ A function is independent and it can perform it’s task without intervention
from or interfering with other parts of the program.
∙ A function performs a specific task. A task is a distinct job that your
program must perform as a part of it’s overall operation, such as adding
two or more integers, sorting an array into numerical order, or calculating
a cube root etc.
∙ A function returns a value to the calling program. This is optional and
depends upon the task your function is going to accomplish. Suppose you
want to just show few lines through function then it is not necessary to
return a value. But if you are calculating area of a rectangle and wanted to
use the result somewhere in program then you have to send back (return)
value to the calling function.
C language is collection of various in-built functions. If you have written a pro-
gram in C then it is evident that you have used C’s in-built functions. printf,
scanf, clrscr etc. all are C’s in-built functions. You cannot imagine a C
program without function. There are three steps in using functions, they are
1. Function declaration (function prototype): The syntax for function
declaration is
type name(arguments);
2. Function definition: The syntax for this is
type name(arguments){statements}
3. Function calling
36
52. 8.1 Passing Values to Arguments 37
The function declaration and definition can be made together. The function
declaration should be made before calling the function. But function definition
need not be defined before calling it can be done even after calling. Let’s see a
small code:
/**A program to find area of square **/
#include <stdio.h>
double find_area(double);
int main ()
{
double side ,area;
printf("nEnter the length: ");
scanf("%f" ,&side);
area=find_area(side);
printf("nThe area of the square is: %f n",area);
return 0;
}
double find_area(double leng)
{
return(leng*leng);
}
Program 8.1: Area of Square
The above code displays some features.
∙ At first we see that the function find area() is declared if not the com-
piler will show an error.
∙ Then you can see that the argument list in the function declaration consist
only of the data type of variable used and not the variable name used. The
variable name is not necessary in the argument list during declaration but
it is compulsory in the argument list of function definition.
∙ We have also seen how the function returns a data and so it can be used
in expressions.
∙ The variable leng is called the formal argument and side is called actual
argument. We can say that formal arguments are the arguments that we
define in function declaration and actual arguments are arguments that
we pass to the function during function call.
8.1 Passing Values to Arguments
In the previous example we saw that the length of the square was given as
an argument to the function find area(), the function used this argument for
further calculation.
The argument list can contain as many arguments as required, it can even
be zero. The data type of each argument should be given separately even if they
all are of the same type. In case there are arguments then we should learn how
the values we give as input is passed to the arguments in the function.
The arguments are passed to the functions by
1. Pass by value
2. Pass by reference using pointer method
53. 38 8. Functions
The pointer method will be dealt with in a later chapter.
8.1.1 Pass by Value
In this method we make a copy of the original variable and the function operates
on that copy, so the original variable is not affected.
8.1.2 Pass by Reference
In this method we refer to the function the original address where the variable
is stored and the function operates directly on that variable, so changes that
the function brings about on the variable is reflected on the value stored in the
variable itself. There are two methods to do this.
∙ Using reference variables - C does not support this method
∙ Using pointers
You may find several sources with arguments on this topic, some say that C
does not support pass by reference at all, and that the pointer method cannot
be called a pass by reference method, but this does not matter because all we
need is a program to work as we wish.
8.2 The return Statement
We have seen that a function itself has a data type, this indicates what type of
value the function will return after it’s execution, so all functions except the one
with void as data type should have at least one return statement. During the
execution of a function only the first return statement will be executed because
a function exits as soon as it encounters a return statement.
int my_fun(int a,int b)
{
if(a>b)
return a;
else
return b;
}
In the above code the function returns the greatest of the two values passed
to it, as soon as it meets one return statement the function execution is over.
For functions with void as data type the closing braces (}) acts as an automatic
return statement.
8.3 Functions with Variable Argument List
Perhaps you would like to have a function that will accept any number of values
and then return the average. You don’t know how many arguments will be
passed into the function. One way you could make the function would be to
accept a pointer to an array.
54. 8.3 Functions with Variable Argument List 39
Functions in C can also have an argument list that varies in length, for that
we use an operator called ellipsis which consists of three (.) without any space
between them. The function prototype will be
int fun(int num , ...);
Indeed, some library functions can accept a variable list of arguments (such
as printf—I bet you’ve been wondering how that works!).
Whenever a function is declared to have an intermediate number of argu-
ments, in place of the last argument you should place an ellipsis (which looks
like ‘. . . ’), so,
int a_function(int x, ...);
would tell the compiler the function should accept however many arguments
that the programmer uses, as long as it is equal to at least one, the one being
the first, x.
To use these functions, we need a variable capable of storing a variable-
length argument list—this variable will be of type va list. va list is like any
other type.
va start is a macro which accepts two arguments, a va list and the name
of the variable that directly precedes the ellipsis (“. . . ”). So in the function
a function, to initialize list with va start, you would write va start(list,
x);
int a_function(int x, ...)
{
va_list list;
va_start(list , x);
}
va arg takes a va list and a variable type, and returns the next argument
in the list in the form of whatever variable type it is told. It then moves down the
list to the next argument. For example, va arg(a list, double) will return
the next argument, assuming it exists, in the form of a double. The next time
it is called, it will return the argument following the last returned number, if
one exists. Not that you need to know the type of each argument—that’s part
of why printf requires a format string! Once you’re done, use va end to clean
up the list: va end(a list);
To show how each of the parts work, take an example function:
#include <stdarg.h>
#include <stdio.h>
float average(int num , ...)
{
va_list arg;
float sum =0;
int x;
/* Initializing arguments to store all values
after num */
va_start(arg ,num);
/* Sum all the inputs; we still rely on the
function caller to tell us how many there are */
55. 40 8. Functions
for(x=0;x<num;x++)
{
sum += va_arg(arg ,float);
}
va_end(arg); // Cleans up the list
return sum/num;
}
int main ()
{
printf("%fn",average (3, 12.2, 22.3, 4.5));
printf("%fn",average (5, 3.3, 2.2, 1.1, 5.5, 3.3));
}
Program 8.2: Variable argument list
In the variable-length part of variable-length argument lists, the old “default
argument promotions” apply: arguments of type float are always promoted
(widened) to type double, and types char and short int are promoted to int.
Therefore, it is never correct to invoke va arg(argp,float); instead you should
always use va arg(argp,double) Similarly, use va arg(argp,int) to retrieve
arguments which were originally char, short or int. (For analogous reasons,
the last “fixed” argument, as handed to va start, should not be widenable,
either.)
It isn’t necessarily a good idea to use a variable argument list at all times;
the potential exists for assuming a value is of one type, while it is in fact another,
such as a null pointer being assumed to be an integer. Consequently, variable
argument lists should be used sparingly.
8.4 Scope of a Function
The scope of a function shows in what parts of a program code the function
is available. If a function is defined within main() then that function can be
used only in the main() of that code. Usually functions are declared outside
the main().
If we use the type qualifier static then the function is available only in the
source code where it’s definition is made. By default the type qualifier for a
function is extern. This shows that the function can be defined in some other
source file.
Also global variables are accessible by all functions but a variable declared
within a function is accessible only by that function. Any source file needing to
use a function in another source file should declare it.
8.5 Arrays as Arguments
Arrays can also be used as arguments to a function. In this case during function
declaration or definition the size of array may or may not be specified. Also
we’ve seen earlier that the name of an array also denotes the address of the
array so array arguments acts much like pointer arguments which we will see
in the coming chapter. The effect is that any change that we bring to array is
reflected because here the arguments are not passed by value i.e. the compiler
doesn’t pass the copies of the arguments but it passes the arguments itself. The
56. 8.6 Recursive Functions 41
reason that the size of array is irrelevant in the function declaration is because
the array name is treated as an address location and the memory from that
location onwards is monitored by the function, but the programmer should take
care that the memory being accessed does not contain garbage values.
#include <stdio.h>
void fun(int arr[],int len)
{
int i;
for(i=0;i<len;i++)
{
printf("n%dn",arr[i]);
}
}
int main ()
{
int a[]={1 ,2 ,3 ,4 ,5};
fun(a,5);
return 0;
}
Program 8.3: Arrays as arguments
The above program prints out the elements in an integer array. Here the
programmer has to give size of array in the main() or else the function will not
know till when to read and it might read out some garbage values.
8.6 Recursive Functions
Recursion is a method where the solution to a problem depends on solutions
to smaller instances of the same problem. Recursion is a method used in Com-
puter Science to breakdown larger problems into smaller ones, there are a lot
of mathematical problems that use recursion. The factorial, Fibonacci series
etc. . . . all can be implemented by recursion. As the name suggests recursive
functions are functions that repeat in loop until terminated by some condition.
These are functions that refer back to themselves so they go on being executed.
In a programming language, recursive functions are an inefficient means of solv-
ing problems in terms of run times but are interesting to study, they simulate
the effect of using a stack. The property of a stack can be understood by con-
sidering a pile of books. When we place a new book to the pile (This is called
pop) it goes on top and the book that was on top first is pushed one position
down, while removing a book (This is called push) from that pile we move the
topmost or we use the LIFO (Last In First Out). Let’s see a program that finds
the factorial of a given number.
#include <stdio.h>
int fact(int num)
{
if(num <=1)
return 1;
else
{
return(num*fact(num -1));
}
}
int main ()
57. 42 8. Functions
{
int result ,num;
printf("nEnter the number: ");
scanf("%d" ,&num);
result=fact(num);
printf("nThe result is %d n",result);
return 0;
}
Program 8.4: Factorial
In the above program the function fact() calls itself (This is called imme-
diate recursion) and thus it goes on till the variable num=1. Suppose the input
was three,
∙ In the first stage we get 3*fact(2)
∙ Then we gave 2*fact(1)
∙ fact(1) will return 1 so going back to the top we get 1*2
∙ This is returned to the outer fact() and we get 3*(1*2). Thus the
factorial of 3 was obtained.
All recursive functions can be rewritten with loops but making recursive func-
tions saves a lot of code. But care has to be taken that the recursive function
exits at some point of it’s execution and that it does not fall into an infinite
loop. Sometimes recursive functions are a bit tricky to understand even for a
well experienced programmer.
Tower of Hanoi
Almost every textbook that speaks about recursion in programming mentions
this famous puzzle. The Tower of Hanoi is a mathematical game or puzzle. It
consists of three rods, and a number of disks of different sizes which can slide
onto any rod. The puzzle starts with the disks in a neat stack in ascending
order of size on one rod, the smallest at the top, thus making a conical shape.
Figure 8.1: Tower of Hanoi
The objective of the puzzle is to move the entire stack to another rod, obeying
the following rules.
∙ Only one disk may be moved at a time.
58. 8.7 Command Line Arguments 43
∙ Each move consists of taking the upper disk from one of the rods and
sliding it onto another rod, on top of the other disks that may already be
present on that rod.
∙ No disk may be placed on top of a smaller disk.
A key to solving this puzzle is to recognize that it can be solved by breaking the
problem down into a collection of smaller problems and further breaking those
problems down into even smaller problems until a solution is reached.
8.7 Command Line Arguments
It has already been mentioned that main() is also a function, this function also
has three arguments, the original form of the main() function is:
int main(int argc , char *argv[], char envp []);
The function main() has a return type of int and the exit code is the value
that the main() function returns. This is a number that is used by the OS to
detect whether the function exited properly or if there was any error. Usually
we return zero to denote a success in execution.
Before I explain the arguments let’s once again look at how we execute a
program from the shell.
Let the program name be prog, then at the terminal we type:
$ ./prog
($ symbol shows the command prompt, it is not to be typed). We can provide
values to the arguments right after the program name. Let copy be a program
to copy contents of one file to another then the program will be executed by
issuing the following command.
$ ./copy file1 file2
Here file1 and file2 are two arguments passed to the program copy. Now
let’s discuss the arguments in the main().
∙ int argc: This is the argument that keeps count of the number of words
appearing on the command line that invokes the program and the count
includes your program name also. In the above example, the value in
argc will be 3 (copy, file1, file2). The argc value will be at least
one because it counts the program name.
∙ char argv[]: This is a character array that contains the words including
the program name. In the above example the array will be
argv[]={copy,file1,file2}.
∙ The last variable is environment variable which contains details about
the environment in which the program is being executed, it lists out the
environment variables.
The argument argc and argv are conventional names, we can use any other
name.
Let us now see a program that elaborates on the command line arguments.
59. 44 8. Functions
#include <stdio.h>
int main(int argc ,char *argv [])
{
int i;
printf("n The number of arguments is: %d
n" ,(argc -1)); /* argc contains count of
program name also */
printf("nnnaaaaaaThe arguments are: n");
for(i=0;i<argc;i++)
{
printf("%s",argv[i]);
}
printf("nn");
return 0;
}
Program 8.5: Command line arguments
The readers can now write a program to list out the environment variables.
There are a lot of environment variables and when you execute the program
you will see that there is a big list of variable being displayed, at present these
variables are not of much importance but you can search the Internet to learn
more about the shell and the environment variables. Some of the simplest
environment variables are those which contain the path of the current working
directory, path of the home folder etc.
8.8 Exercises
1. Write a function using recursion to print numbers from 𝑛 to 0.
2. Write a function using recursion to enter and display a string in reverse and
state whether the string contains any spaces. Don’t use arrays/strings.
3. Write a function using recursion to check if a number 𝑛 is prime. (You
have to check whether 𝑛 is divisible by any number below 𝑛.)
4. Write a function using recursion to enter characters one by one until a
space is encountered. The function should return the depth at which the
space was encountered.
5. Write a function that accepts two matrices and returns the product if they
can be multiplied.
6. Write a program that takes argument from command line and returns the
number of upper case letters used.
60. Chapter 9
Pointers
Pointers are the most important and most powerful concept of C. An experienced
C programmer can handle pointers easily whereas it makes programming a
nightmare for beginners. The reason is that beginners fail to grasp the concept
of pointers and related fields like dynamic memory allocation etc.
The pointer is another type of variable which stores the address of a variable,
a pointer is a variable that points to the memory location of a variable of a
particular type. The pointer variable can store address of an int, float,
char, structure or even of a pointer variable itself. We can also declare a
pointer with void data type. A pointer variable is declared as:
type *variablename;
The * is what distinguishes a normal variable from a pointer variable. Some
examples for pointer declaration are:
int *mypoint;
float *charpoint;
We know that an integer variable has 2 bytes length, a float has 4 bytes
and a character variable has 1 byte length. The pointer variable for all data
types has 1 byte memory. All that a pointer variable does is that it stores the
address of a variable so it has only 1 byte memory. In C the name of an array is
actually a pointer to the address of the first element of the array. The process
of reading the value stored at a particular memory address in a pointer is called
dereferencing. We have used the & in the scanf(), have you ever wondered
what the symbol stands for, it is used to denote the address of the variable,
suppose you have a normal integer variable called var and you want its address
then we use &var to denote it’s address. It is actually the address of the variable
that we pass to the scanf().
int a=10,b, *point;
point =&a;
b=* point;
In the above code we declared two normal integer variables and a pointer to
integer variable. In the second statement we stored the address of the integer
variable to the pointer variable. The next statement is called dereferencing, the
value stored at the address denoted by point is being retrieved. It is to be
noted that we use the asterix itself to dereference a pointer variable.
45
61. 46 9. Pointers
9.1 Pointer Arithmetic
The pointer variable can be incremented, decremented and value in the pointer
variable can be assigned to another variable. These are the only arithmetic
operations that can be performed on the pointer variables. The pointer of same
data types can be compared.
#include <stdio.h>
int main ()
{
int a=10,* point;
point =&a;
printf("n %d: ",point);
printf("n %d: " ,*point);
printf("n %d: " ,++(* point));
point ++;
printf("n %d: n" ,*point);
return 0;
}
Program 9.1: Pointer Arithmetic
In the above program let’s assume the address of the variable a is 100. In
the first printf statement the address 100 is printed, in the second printf
statement the pointer is dereferenced and the value 10 stored in it is displayed.
In the third statement the value stored at location 100 is incremented and
printed, and finally the point++ increments the address value. The question
is by how much does the address increase? If your answer is that it increases
from 100 to 101 then it’s wrong, the address value in point increases by 2 bytes
because the integer data type is of 2 bytes size. The same is applicable for the
decrement operator also. The statement
printf(‘‘n %d:’’,*point ++);
In this statement the value at location point is dereferenced and then the
address in point is incremented.
9.2 Call By Reference
We have seen that when we pass arguments to functions only copies are passed
and not the real variables themselves, this is called pass by value. Pass by
reference is a method in which we pass the original variables themselves therefore
if the function brings about a change in the value of the variable this value is
reflected in the original variable itself. We know that a function can return only
one value, it can have only one return statement. But we can use the concept
of pass by reference to return more than one value from the function.
#include <stdio.h>
int div(int a,int *rem)
{
int var1;
var1 =*rem;
*rem=a%var1;
return(a/var1);
}
int main ()
62. 9.3 Pointer to Function 47
{
int a=5,b=2,c;
c=div(a,&b);
printf("nQuotient =%d nRemainder =%d n",c,b);
return 0;
}
Program 9.2: Call by reference
In the above program we have defined a function div() such that it returns
the quotient after division of two numbers and the remainder is returned by
call by reference method because the second number to be divided is passed by
reference and the remainder is stored in it. As the second argument we pass
address of the variable b.
9.3 Pointer to Function
We know that functions return values corresponding to the data type of the
function. Functions can also return pointers. In such a case the function decla-
ration will be as below:
data type *function_name(<arguments >);
Obviously the return statement of the function should return an address.
But this is not the pointer to function concept and readers should not confuse
themselves. A pointer to function declaration is as follows:
data type (* function_name)(<arguments >);
Function pointers provide some extremely interesting, efficient and elegant
programming techniques. You can use them to replace switch/if statements.
Function pointers are pointers, i.e. variables, which point to the address of a
function. You must keep in mind, that a running program gets a certain space
in the main memory. Both the executable compiled program code and the
used variables are put inside this memory. Thus a function in the program
code, is like character field, nothing else than an address. It is only important
how your compiler/processor interpret the memory a pointer points to. The
function pointer can be used to store that address and that pointer can be
used to dereference and call the function. A function pointer invokes a function,
passing it zero or more arguments just like a normal function. Function pointers
can be used to simplify code by providing a simple way to select a function to
execute based on run-time values.
#include <stdio.h>
float Plus(float a,float b) // Function to add
{ return a+b; }
float Minus(float a,float b) // Function to minus
{ return a-b; }
float Multiply(float a,float b) // Function to
multiply
{ return a*b; }
float Divide(float a,float b) // Function to divide
{ return a/b; }
// Function with pointer to function as argument
63. 48 9. Pointers
void calculator(float a,float
b,float (* point)(float ,float))
{
float res=point(a,b); // Call using function
pointer
printf("The result is: %f n",res);
}
int main ()
{
calculator (2,5,& Minus);
return 0;
}
Program 9.3: Pointer to function
The & in &Minus is not compulsory, we can write that statement as
calculator (2,5, Minus);
In the above program the function calculator() accepts two floating point
numbers and a pointer to the function Minus(). In the function calculator()
the pointer is used to call the corresponding function and the floating point
numbers are used as arguments of that function and the result is printed. The
function pointer does not increase speed of calling function but it makes a
function similar to a variable and it can be passed to another function as an
argument, it can be assigned to another pointer variable etc. The function can
almost be treated as a normal variable.
9.4 Pointers and Arrays
We have already discussed that the name of an array refers to the memory
location of the first element of the array. The other members are accessed by
incrementing the memory address from there as we saw in pointer arithmetic.
We can also declare an array of pointers which will contain a collection of the
address values.
int num [10] ,*p,a,* parray [10];
p=num; // Valid statement as both contain address
a=p; // Invalid statement
Here the name num references to the location of integer stored in num[0], so
the value of num can be assigned to the pointer variable p. If the argument list of
a function contains a pointer variable of a type, then during function call we can
pass an array of the same type to the function. The use of pointer arguments
instead of arrays can simplify the code, but in order to handle pointers you
should be well versed with it.
Strings are also arrays of characters. We can access strings using pointers
just as we did for a normal array because a string is also a normal array but the
end of a string is indicated by the NULL character 0. We can use this idea to
detect end of a string.
#include <stdio.h>
void readstr(char *msg)
{
int i;