C Programming Language Complete Reference 2021
C Programming Language Complete Reference 2021
Notice of Rights
No part of this publication may be reproduced, transmitted, transcribed, stored in a
retrieval system, or translated into any language or computer language, in any form or
by any means, electronic, mechanical, magnetic, optical, chemical, manual, or
otherwise, without the prior written permission of AH CAREER Pvt. Ltd.. except under
the terms of a courseware site license agreement.
Trademark Notice
Throughout this courseware title, trademark names are used. Rather than just put a
trademark symbol in each occurrence of a trademarked name, we state we are using
the names only in an editorial fashion and to the benefit of the trademark owner with
no intention of infringement of the trademark.
Notice of Liability
The information in this courseware title is distributed on an ‘as is’ basis, without
warranty. While every precaution has been taken in the preparation of this course,
neither the authors nor AH CAREER Pvt. Ltd.. shall have any liability to any person or
entity with respect to any loss or damage caused or alleged to be caused directly or
indirectly by the instructions contained in this book or by the computer software and
hardware products described in it.
Disclaimer
We make a sincere effort to ensure the accuracy of the material described herein;
however, AH CAREER Training Materials makes no warranty, expressed or implied,
with respect to the quality, correctness, reliability, accuracy, or freedom from error of
this document or the products it describes. Data used in examples and sample data
files are intended to be fictional. Any resemblance to real persons or companies is
entirely coincidental.
All information in this manual was correct at the time of writing. AH CAREER is not
affiliated with nor has any control over changes made to the product described in this
manual. These include, but are not limited to, changes in the application’s color
scheme, icon appearance and locations, addition or removal of program features,
online templates, and help content. AH CAREER reserves the right to make corrections
to the courseware at any time and without notification.
Foreword
This material has one to one correspondence with the instructions in the class.
This will be supplementary reading material to the classroom instructions.
1. Before attending the class, browse through the corresponding sessions material
3. Immediately after the lecture, go through the sessions till you understand the concept
totally.
We have tried to ensure that there are no major technical or grammatical errors
in this material. But in a work of this magnitude, some small errors are bound to creep
in. As student you are likely to go through every line of this material. If you notice some
errors, please let us know through the feedback sheet (available at the end of this book,
please hand it over to our office). Your feedback will help to us to design more effective
and error free material in future.
We would like to wish you every success in your determined efforts to master
computers.
AH CAREER
Index
1. Introduction
2. to
Programming
Topic # 1
Atish Jain
Now a days usage of a Computer has become a part of our everyday life, Lets see
various areas where computers are useful to humans, so that you don’t have any doubt
in your mind about its applications
• Computerized Banking
• Reservation of Rail, Air and Bus tickets – online
• Online Bill Payments
• Email, E-Commerce / E-Shopping
• Using websites for viewing of Exam Results
• CAD (Computer Aided Designing) & CAM (Computer Aided Manufacturing)
• Medical Examination
• Finger Print Verification – in Crime Investigation
• Shopping Malls – bill generation
• Animation in Movies – Avatar (Hollywood), Eega (Tollywood)
• Mobile Phones, Online Examination System etc
S1. Algorithm / Logic Preparation: Preparing the plan to solve the particular problem.
It contains the steps which are to be performed to get the work done by a
Program/Software. It is independent of the programming language that we are going to
use.
Algorithms are expressed in two ways:
▪ Pseudo code.
▪ Flowchart.
Pseudo code
Pseudo code is a short hand way of describing a computer program. Using Pseudo code,
it is easier for a non-programmer to understand the general workings of the program.
Flowchart
Flowchart is a graphical representation of an Algorithm.
Flowchart Symbols - Some of the basic symbols used in flowcharting.
Flowchart symbols:
➔ Start/Stop
Terminator
Parallelogram ➔ Input/output
➔ Process
Rectangle
➔ Decision making
Diamond
➔ Connector
Circle
➔ Flow lines
Print c
Stop
Step1: start
Step2: read a,b Start
Step3: if a>b then
print a is big
else Read a,b
print b is big
Step4: stop
yes If a>b no
Print Print
a is big b is big
Stop
No = No+2
yes
If No<=100
no
Stop
• Write the Pseudo code and draw the corresponding flowchart to calculate
Interest for the Input principle amount, time and rate of interest.
• Write the Pseudo code and draw the corresponding flowchart to check whether
the student has passed or failed from the input marks for 3 subjects.
• Write the Pseudo code and draw the corresponding flowchart to print 5th table till
12.
S3. Compilation / Transformation: The code that we write is known as Source Code. It
is close to English. But any computer ultimately understands only Binary
Code/Machine Language. So our Source Code has to be converted into Machine Code.
Converting the Source code (the program which we write) into machine language is
known as Compilation. This Job is done by special software – Compilers , Interpreters.
S4. Execution: Passing the Machine Code instructions to the computer to get the
Output (result). First the Machine Code has to be loaded into main memory of the
computer i.e,. RAM, then the CPU takes instruction by instruction from RAM, processes
it and gives the result.
The logic preparation, is generally the most difficult part of the programming.
There are several programming languages – some are more popular in specific domain
areas, some are very widely used in several domain areas
A Program is nothing but text which is comprised of alphabets, digits & special
sysmbols.
Programming
Languages
Assembly Level
Machine Level Language
Language
(Numbers language)
(Symbols Language)
Binary Numbers
Decimal
Octal Numbers,
Hexa decimal numbers
Early computers systems were literally programmed by hand. Front panel switches
were used to enter instructions & data. These switches represented the Address, Data
& the control lines of the computer system.
Machine languages required the writing of long strings of binary no.s to represent such
operations as “add”, “sub”, “compare” etc. Later improvements allowed octal, decimal
or hexadecimal representation of the binary strings.
• Any computer can directly understand only its own machine language.
• Machine language is the natural/nature language of a particular computer.
• It is defined by the H/W design of that computer.
• Machine code languages generally consist of strings of numbers
(decimal/hexadecimal/octal, which are ultimately reduced t o 0’s and 1’s) that
instructs computers to perform their most elementary operations one at a time.
• Machine code language programs are machine code dependent. i.e., a particular
machine code language can be used on only one type of computer.
• Machine code language programmers must have sound knowledge of how a
particular computer performs its elementary operations (arithmetic & logical). As
computer became more popular, it became apparent that machine code language
programming was:
• Too slow (Program development)
• Difficult to code
• Error prone
• Not portable on different types of computers.
Instead of using the Strings of numbers that computers could directly understand,
programmers began using English – like abbreviations to represent the elementary
operations of the computer.
Assembly language allows programmer to use symbolic addresses, which are later
converted to absolute addresses by assemblers.
Advantages
• We can use mnemonics (abbreviations) like MOVE, CLEAR while writing source
code.
• Changes could be made easier & faster.
• Easier to read & write (program development is faster)
• Error checking is provided.
• Variables are represented by symbolic names, not as memory locations.
Drawbacks
Software
▪ Set of programs which perform a particular task.
▪ There are two types of Softwares:
Software
Packages Languages
System software
▪ The software which is used to start the computer system or the software which
makes the hardware parts of the computer system functioning is known as
system software.
▪ E.g. DOS, Windows, UNIX, Linux etc...
▪ System software is also known as Operating System or OS.
Application software
▪ The software which performs a particular task is known as application software.
Application software is used to perform user tasks.
Package
▪ Set of pre-written programs to solve a particular task.
▪ E.g. Word, Excel, tally etc…
Language
▪ Set of keywords, which are used to write a program.
▪ E.g. BASIC, COBOL, C, FORTRAN, PASCAL etc…
Language Package
1. Set of keywords 1. Set of pre-written programs
2. Develops system software 2. Develops application
3. No programming Boundaries software
4. Not user friendly 3. Programming boundaries
E.g. Basic, Cobol etc… 4. User friendly
E.g. Excel, Tally etc…
Exercise
2. C Basics
Topic # 2
Atish Jain
2. C Basics
2.1 What is ‘C’?
C was originally designed for and implemented on the UNIX OS on the DEC PDP – II
computer by Ritchie. The Unix OS (near about 95%), the C Compiler and essentially
all UNIX application programs are written in C.
We know that a book is a collection of chapters where each chapter deals with a
topic; similarly a ‘C’ language program is nothing but a collection of functions, where a
function is a block of code, which performs a particular task. Hence C language is
called as procedural programming language.
All Software Engineering Aspirants should start with “C”. Everyone has it in their
Academics – BTech, MCA, BSc Computers etc
C is a Middle Level Language; it has the features of both low-level languages and
high-level languages. i.e., software development is relatively faster than assembly
language (low level) and program execution is relatively faster than other high – level
programming languages.
Communication with the Hardware is easy which was earlier possible only with
assembly languages.
• System programming
• General application programming
• Embedded systems programming
• Game Programming
• Network programming.
Most of the Software in the world were developed using C/C++. The
world’s software giants, Microsoft, Borland develop most of their software
using C & C++.
In fact anything and every thing that can be done on computer, can be done using
‘C’, provided we are good at it and the particular programming domain.
C was invented to create a portable Operating System and the first portable Operating
System was UNIX
Features of C language:
1. Portability:
C programs are portable, they can be transferred to any other system for execution.
2. Modularization/structured language:
A lengthy program can be divided into modules.
6. Case sensitive
It means Capital letters are different from small letters.
7. Function oriented
Entire program is written as a collection of functions. There are nearly 400+ functions
in c language.
History of C language:
• Editor
• Preprocessor
• Debugger
• Compiler
• Linker
• Standard Object Library
• Header Files
• Help Document.
Program 2.1
Welcome to C
Turbo C IDE
After typing the program follow these steps:
Step 1 : Save your program using the File menu of your Turbo C IDE.
Step 2 : Compile -> Alt + F9
Step 3 : Link -> F9
Step 4 : Execute -> Ctrl + F9
Step 5 : To view the result -> Alt + F5
Explanation
a) The same program could have been written in two more ways.
ii.) main()
{
printf(“Welcome to C”);
}
Method (i) (Program 2.1) and (iii) are perfectly correct but method (ii) is not, some
will understand the difference between them at the end of Chapter 5 (Functions).
b) Earlier we learned that a C Program is nothing but a collection of functions. There
can
be any number of functions in a program, main() is the compulsory function in
a C program because it is both the entry point and exit point of a program
c) Parentheses are used to indicate a function.
d) A function contains a set of instructions enclosed with a pair of braces ({ and })
e) printf() is a library function which is used to print a message (with in double
quotes) on
the screen.
f) void : it indicates that the main() function doesn’t return any value.
g) Every instruction must be terminated with a semicolon.
How to Open Turbo C IDE on a 64-bit Windows OS
Note: Turbo C IDE is a 16-bit Application. A 16-bit application can be run a 32-bit
Architecture, but not on a 64-bit Architecture, so its backward compatibility is only
upto 32-bit architecture.
However we can use DOS Emulator software using which we can run a 16-bit
application on a 64- bit Architecture. DOSBox is one such software
Step3.
From:
To
Note: For compilation, linking, execution and viewing the output, better use the
menu options
instead of ShortCut keys as some of them may collide with the shortcut keys of DOSBOX
What is DOSBOX?
As we all know the Popular Turbo C 3 [C and C++ compiler by Borland] does not run
well on 64 bit OS’s like Windows 7, Windows 8 etc., and on 32 bit OS’s they can’t work
full screen, so we have developed the emulated version of the same TurboC compiler
within an environment called DosBoX which works on all OS’s Full screen
Eg: http://www.tutorialspoint.com/compile_c_online.php
It’s a Linux based Compiler
We have used C-Free Evaliaton version editor to run all programs in this book. It is one
the best C IDE available online.
Use following steps to write any C program in C-Free editor
C-Free is a professional C/C++ integrated development environment (IDE) that support
multi-compilers. With this software, user can edit, build, run and debug programs
freely. With C/C++ source parser included, although C-Free is a lightweight C/C++
development tool, it has powerful features to let you make use of it in your project.
Click on Finish
Language Elements
• Identifier
o Names of variables/functions
• Standard datatypes
o To specify the type of data.
• Constants
o Constant is an entity that doesn’t change.
o Ex: character, Integer, float, String
Note:
The difference between float and double is the precision.
float – 6 digits.
double – 15 digits.
Any program is meant for processing some kind of input data & get desired results. The
microprocessor device processes data. The microprocessor can process data only if the
data is available in RAM (primary memory). To store any data in RAM we have to
reserve required amount of memory.
Reading a number from the Keyboard, storing it in the memory & then printing it on
the screen
Program 2.2
void main()
{
int n;
printf("Enter a number:");
scanf("%d", &n);
printf("%d", n);
}
output
Enter a number: 786
786
Explanation
a) int n;
this statement tells the compiler to reserve sufficient amount of memory to store an
integer (number) value(2 bytes for an integer) and give a name ‘n’ to that memory
location.
• int is called as datatype.
• ’n’ is the variable name
• variable is the name given to a memory location where a constant value is stored.
b) scanf() is a library function which is used to accept a data item from the keyboard
& store it in the specified memory location.
c) %d called as format specifier. It tells the compiler that we are going to read a
decimal number.
d) & is called as address of operator
e) &n tells the compiler to store the accepted value in the location whose name is n.
f) note that & is required only in the scanf() function, but not in the printf() function.
Why? the reason you will understand at the end of pointers (chapter 7)
Program 2.3
void main()
{
char ch;
printf("Enter a character:");
scanf("%c", &ch);
printf("%c", ch);
}
Output
Enter a character: y
y
Explanation
a) char is a datatype
b) Only one byte is allocated for a char type of value.
c) Remember that characters are internally stored as integers.
Program 2.4
void main()
{
float f;
printf("%f", f);
}
Output
Enter a fractional value: 12.79
12.79
Explanation
a) float is a datatype
b) Four bytes are allocated for a float type of value
Program 2.5
void main()
{
char na[30];
printf("Enter a name:");
scanf("%s", na);
printf("%s", na);
}
Output
Enter a name: Raju
Raju
Explanation
Program 2.6
void main()
{
int a, b, c;
c = a + b;
Output
Explanation
a) ‘+’ and ‘=’ are operators in C, whereas ‘a’, ‘b’, ‘c’ are operands. Operand is an entity,
which can be a variable/constant/ expression. Note that the left side of ‘=’
operator can be only a variable.
b) The value of a+b is assigned to the variable C
2.8 Keywords
Keywords are nothing but reserved or predefined words. This is the actual part of any
language. (Kernel of the language). ‘C’ language has 32 keywords . These are shown
below.
int unassigned do auto
char sizeof break static
float const continue register
long volatile goto extern
short if switch struct
double else case typedef
void for default union
signed while return enum
Translators are the programs which converts source code into machine code. The
Different translators are.
▪ Assemblers – for Assembly language
▪ Compilers – for HLL
▪ Interpreter – for 4GL’s
Compiler:
Interpreter:
Conclusion:
2.9 Errors
Compile time errors : These errors can occur during the compilation (infact debugging
) which occurs just before compilation of a program. these errors occur if we violate ‘C’
language rules & regulations. only after correcting these errors the program can be
compiled.
Examples
a) Missing semicolon at the end of an instruction.
b) Forgetting to define a variable.
Linking errors
Usually program development in C, C++, Java etc languages, employs add-on strategy
i.e., instead of developing everything from the beginning, we use some readymade
components, so that our program development would be faster. These readymade
components (in ‘C’ language known as library functions) are usually available in
machine – code format (Object – code).
Linking is a process of combining the machine code versions of our source code with
the machine code versions of the library functions.
If there is any problem during this process, then the linker software reports a linking
error.
examples
Logical errors
These errors occur if there is any mistake in the logic of the program written.
What we get is incorrect results. We can identify that there is a logical error only if
we know in advance what should be the result of a program.
Runtime errors
The errors, which occur during the execution of a program, are called as run time
errors.
Examples
A software success depends on how far the run time errors have been tackled. Hence
60 – 80 % of the program development time is spent on detecting & correcting runtime
errors.
2.10 Typecasting
Program 2.7
void main()
{
int a, b;
float c;
c = a / b;
Output
Explanation
The output is not as expected isn’t it? We expected 2.5 but the result is 2.0
Why?
The rule is like this:
When an arithmetic operation takes place between two operands :
Program 2.8
void main()
{
int a, b;
float c;
Output
Explanation
c= (float) a/b;
When this statement gets executed, the value of ‘a’ is temporarily promoted to float
value & have the output.
2.11 Operators
In the following table of operator precedence, the Turbo C operators are divided into
16 categories.
The #1 category has the highest precedence; category #2 (Unary operators) takes
second precedence, and so on to the Comma operator, which has lowest precedence.
The operators within each category have equal precedence.
The Unary (category #2), Conditional (category #14), and Assignment (category #15)
operators associate right-to-left; all other operators associate left-to-right.
This is a binary operator (has two operands), which give the reminder.
Remember that the operator should be of integral type only.
Program 2.9
void main()
{
int a, b, c;
Output
getch() . It happens to be one more library function. It stands for get a character from
the keyboard buffer area.
Use
Till now we have been viewing our output by pressing Alt + F5. Instead use getch()
function at the end of the program which helps in displaying the output until the user
presses any key.
Example
Suppose that we want to check the reminders of different sets of values, so every time,
after executing the program we have to press Alt + F5 to view the result. getch() usage
will avoid this frequent usage of ALt +F5
There are many other applications of getch() function which we will discuss later. The
following program illustrates the usage of both these functions
Program 2.10
void main()
{
int a, b, c;
printf("Enter two numbers:");
scanf("%d%d", &a, &b);
c = a % b;
printf("Remainder is %d", c);
getch();
}
Explanation
Remember that variables must be defined at the top of a block. i.e., before the first
executable statement in a block.
These are special characters, which performs some formatting operations on the output
to be displayed on the screen. The following program illustrates the usage of some of
the escape sequences
The following program illustrates the usage of some of the escape sequences
Program 2.11
void main()
{
int a, b;
char name[20];
printf("%d\t%d\n%s", a, b, name);
}
Output
Enter two numbers: 23
96
Enter a name: Arnold
23 96
Arnold
2.15 Initialization
Program 2.12
void main()
{
int p = 93;
printf("%d", p);
}
Output
93
Explanation
• Had we not initialized ‘p’ the output would have been some garbage (unknown)
value
• If we know in advance, the initial value of a variable, then it’s better to
initialize it ratherthan putting a value using scanf() function
These are one of the most commonly used operators in ‘C’. Unary operators means that
the operator has only one operand.
Let us discuss the unary operator ++ and – operators in a program if a = 10 (the value
of ‘a’ is 10)
a = 10
To decrease it’s value by 1, there are several methods
1.) a =a-1
2.) a-=1
3.) a- -(post incrementation)
4.) - -a(pre incrementaion)
Conclusion
We can find that a++/ ++a or a--/--a are more compact methods than the other
methods.
You will soon understand about this post and pre incrementaion.
The following program illustrates the usage of these operators.
Program 2.13
void main()
{
int a = 10, b = 17, c = 83, d = 24;
a++;
++b;
c--;
--d;
Output
11, 18, 82, 23
Explanation
Here we can notice that there is no difference between post and pre incrementation,
but there is a slight difference between these two. the following two programs
demonstrates this ;
Program 2.14
void main()
{
int a = 5, b;
b = a++;
Output
6, 5
Explanation
b = a++; is same as b = a; a++;
i.e., first the value of ‘a’ is assigned to ‘b’ and then value of ‘a’ gets incremented
Program 2.15
void main()
{
int a = 5, b;
b = ++a;
Output
6,6
Explanation
b = ++a; is same as a = a + 1; b = a;
i.e., first the value of ‘a’ gets incremented by 1, and then the incremented value gets
assigned to ‘b’ So the difference between the post and pre incrementation /
ecrementation operators can be felt only when they are involved in an expression.
2.17 Datatypes
Till now we have been dealing with int, char & float. Let’s discuss in detail A data type
of a variable tells us three things:
datatypes
Secondary
Primary
(User-
(Built in)
defined)
arrays
Integral Real pointer
structures
float
int
double
char
long double
The following table illustrates various types of data types, respective format specifiers
etc.
Note:-
• There is one more datatype: short – which is relavent on 32-bit compilers only
where “int” occupies 4 bytes, short occupies 2 bytes.
• Even characters are internally stored as integers (ASCII values)
• The important difference between float, double and long double is the precision
they support.
float 6 digits
double 15 digits
long double 17 digits
2.18 Swapping
Program 2.16
void main()
{
int a = 10, b = 20, t;
t = a;
a = b;
b = t;
Program 2.17
void main()
{
char ch1, ch2;
Output
Enter a alphabet in lowercase: b
Equivalent uppercase alphabet is B
Explanation
In C formulae can be easily coded. the following program converts temperature value
from Centigrade to Fahrenheit.
Program 2.18
void main()
{
float cen, fah;
printf("Enter temperature in centigrade scale:");
scanf("%f", &cen);
Output
It is used to get the size of a variable or data type i.e., number of bytes allocated in
memory. The value returned by sizeof is depends on compiler for int datatype.
TurboC compiler bydefault takes short as default modifier for int. So, it gives 2 Bytes.
Whereas C-Free compiler takes long as default modifier for int datatype. So it gives 4
Bytes.
You can see this difference by executing below program in both compilers.
Program 2.19
void main()
{
int x;
char y;
float z;
printf("x=%d\n", sizeof( x ) );
printf("int =%d\n", sizeof( int ) );
printf("y=%d\n", sizeof( y ) );
printf("char=%d\n", sizeof( char ) );
printf("z=%d\n", sizeof( z ) );
printf("float =%d\n", sizeof( float ) );
}
output
x=2
int =2
y=1
char=1
z=4
float =4
If we want that the value of a variable is fixed & should not be changed even
accidentally, then such a variable is defined as const
Program 2.20
void main()
{
const int a = 512;
printf("%d", a);
}
Output : 512
Explanation
Any where in the program if we use ‘a’ in the left hand side of ‘=’ (assignment
operator), the compiler reports an error message.
If we use Turbo C IDE by the time we execute a program, four files would have been
created.
On compiling → .obj (object file , the compiled version of our source code)
On linking → .exe (executable file. this is the file which finally gets executed
and this is the file that will be installed in the target computer)
Exercise
2. 3. Control
Structures
Topic # 3
Atish Jain
3. Control Structures
Till now we have been dealing with sequential program execution, i.e., every statement
in the program would be executed sequentially. It means that :
• A statement can be executed only after the execution of its previous statement.
• Every statement in the program will be executed.
• Each statement will be executed only once.
A program too must be able to perform different sets of actions depending on the
circumstances.
The mechanism, which meets this need, is the decision control structures.
Decision control structures may be further classified into three types:
Comparison operators:
Logical operators:
&& And
|| Or
! Not
if and else are the two keywords which are used to construct selection type of
programming.
Whenever we need to perform a particular action when a condition gets satisfied, then
we use uni – directional decision control structure. It is implemented through the
keyword ‘if’
if ( condition )
{
statements
…
…
…
}
If the condition is TRUE, the block associated with ‘if’ gets executed.
Note If only one statement is associated with an ‘if’ expression then enclosing that
statement within a pair of braces is not compulsory.
Example 1
Program 3.1
void main()
{
char ch;
if(ch == 'y')
printf("Enjoy!");
}
Output
Explanation
If the user presses the character ‘y’ then the ‘if’ expression (condition) becomes TRUE
(satisfied). So the statement associated with it gets executed. If the user presses other
than ‘y’ then the output would be nothing.
Remember that there should not be any semicolon at the end of the ‘if’ expression.
Example 2
Program 3.2
void main()
{
int n;
printf("Enter a number:");
scanf("%d", &n);
printf("%d\n", n);
if(n == 786)
printf("Bismillah");
}
Whenever we need to perform a particular action when a condition gets satisfied and
perform a different action if the condition doesn’t get satisfied, then we use bi-
directional decision control structure. It is implemented through the keywords ‘if’ and
‘else’
Syntax
if ( condition )
{
statements
…
…
…
}
else
{
statements
…
…
…
}
If the condition is TRUE, the statements associated with ‘if’ block gets executed,
otherwise the statements associated with the ‘else’ block get executed.
Example 1
Program 3.3
void main()
{
int m;
printf("Enter marks:");
scanf("%d", &m);
Output
Enter marks : 23
Failed
Example 2
Program 3.4
void main()
{
int n;
printf("Enter a number:");
scanf("%d", &n);
if(n % 2 == 0)
printf("Even");
else
printf("Odd");
}
Syntax
if ( condition )
{
statements
…
…
…
}
else if ( condition )
{
statements
…
…
…
}
else if ( condition )
{
statements
…
…
…
}
else if ( condition )
{
statements
…
…
…
}
…
…
…
else
{
Statements optional
…
…
…
}
The conditions are evaluated in order, if any expression is TRUE, the statements
associated with it are executed, and this terminates the whole chain. The last else part
gets executed when none of the other conditions are satisfied. Sometimes there is no
action for the default, in that case the trailing else block can be omitted.
Example 1
Program 3.5
void main()
{
int m;
printf("Enter marks:");
scanf("%d", &m);
if( m >= 60 )
printf("First class");
else if( m >= 50 )
printf("Second class");
else if( m >= 35 )
printf("Third class");
else
printf("Failed");
}
Output
Enter marks : 46
Third class
Example 2
Program 3.6
void main()
{
int n;
printf("Enter a number:");
scanf("%d", &n);
if( n > 0)
printf("Positive");
else if( n < 0)
printf("Negative");
else
printf("Zero");
}
Loop control structures can also be called as iterative or repetitive control structures.
Whenever we need to repeat a set of instructions, certain number of times, then we use
loop control structures.
• for
• while
• do – while
Syntax
Lets understand its working with the help of a flow chart (pictorial representation of a
control flow).
Example 1
Program 3.7
void main()
{
int i;
Output
Explanation
a) If there is only statement associated with a loop then no need of enclosing it
within the braces.
b) The loop runs till ‘i’ value is <= 100. So when ‘i’ becomes 101 the loop
terminates.
c) Note that there should not be any semicolon at the end of the for loop
expression.
Example 2
To print all the even numbers between 1 to 100
Program 3.8
void main()
{
int i;
Program 3.9
void main()
{
int n, i;
printf("Enter a number:");
scanf("%d", &n);
Output
Enter a number : 9
9* 1= 9
9* 2= 18
9* 3= 27
9* 4= 36
9* 5= 45
9* 6= 54
9* 7= 63
9* 8= 72
9* 9= 81
9 * 10 = 90
9 * 11 = 99
9 * 12 = 108
9 * 13 = 117
9 * 14 = 126
9 * 15 = 135
9 * 16 = 144
9 * 17 = 153
9 * 18 = 162
9 * 19 = 171
9 * 20 = 180
Nested loops
Program 3.10
void main()
{
int i, j;
Output
1, 1
1, 2
1, 3
2, 1
2, 2
2, 3
3, 1
3, 2
3, 3
4, 1
4, 2
4, 3
5, 1
5, 2
5, 3
Explanation
a) When the control reaches the inner loop, only after the complete execution of
the inner loop, the control goes to the modification counter of the outer loop.
b) Within the inner loop, the outer loop’s counter variable’s value remains constant,
whereas the inner loop’s counter variable’s value keeps changing.
A program which read a number and generates that many multiplication tables
Program 3.11
void main()
{
int n, i, j;
printf("Enter a number:");
scanf("%d", &n);
printf("\t");
for(i = 1 ; i <= n ; i++)
printf("%5d", i);
printf("\n\n");
Output
Enter a number : 5
1 2 3 4 5
1 1 2 3 4 5
2 2 4 6 8 10
3 3 6 9 12 15
4 4 8 12 16 20
5 5 10 15 20 25
6 6 12 18 24 30
7 7 14 21 28 35
8 8 16 24 32 40
9 9 18 27 36 45
10 10 20 30 40 50
11 11 22 33 44 55
12 12 24 36 48 60
13 13 26 39 52 65
14 14 28 42 56 70
15 15 30 45 60 75
16 16 32 48 64 80
17 17 34 51 68 85
18 18 36 54 72 90
19 19 38 57 76 95
20 20 40 60 80 100
while loop
Syntax
i.c
while( t.c )
{
statements to be executed
…
…
…
m.c
}
Example 1
To print 1 to 10 numbers
Program 3.12
void main()
{
int i;
i = 1;
while( i <= 10 )
{
printf("%d\n", i);
i++;
}
Example 2
To find the reverse of the given number
Program 3.13
void main()
{
int n, r, rev = 0;
printf("Enter a number:");
scanf("%d", &n);
while( n != 0)
{
r = n%10;
rev = rev * 10 + r;
n = n/10;
}
Output
Explanation
The logic is extract each and every digit, starting from the last digit, multiply it by 10
and find the running sum.
You should know that when we divide a number by 10 the remainder is the last digit of
that
number. You should also know that when we divide a number by 10 the quotient is
except the last digit.
Analysis
n r rev
0
786 6 6
78 8 68
7 7 687
0
Program 3.14
void main()
{
int n, r, sum = 0;
printf("Enter a number:");
scanf("%d", &n);
while( n != 0)
{
r = n%10;
n = n/10;
}
Output
Enter a number : 786
Sum of digits is 21
Note : While performing a running sum we have to initialize the variable with zero(0).
A program which reads a number and finds whether the given number is Armstrong
number or not
Armstrong number: If the sum of cubes of each and every digit is equal to the given
number, then such a number is called as an Armstrong number.
Eg : 153, 371
Program 3.15
void main()
{
int n, r, sum = 0, t;
printf("Enter a number:");
scanf("%d", &n);
t = n;
while( n != 0)
{
r = n%10;
sum = sum + r * r * r;
n = n/10;
}
if( t == sum )
printf("armstrong number");
else
printf("not an armstrong number");
}
Explanation
t = n;
by the time the control terminates the while loop, ‘n’ would be zero. Hence to store the
original value of ‘n’ we used the above statement.
Prime number: a number, which is divisible by one and itself, is called as a prime
number. i.e., a prime number has only two factors, one and itself.
printf("Enter a number:");
scanf("%d", &n);
if(count == 2)
printf("prime");
else
printf("not prime");
}
Explanation
We know that the prime number is divisible by one and itself only, that’s why we
divided the given number with every number within the range of one and itself and
counted the number of factors it have. We know that prime number have only two
factors and hence the condition.
Program 3.16 (b)
(Method-2)
void main()
{
int i, n, count = 0;
printf("Enter a number:");
scanf("%d", &n);
if(count == 0)
printf("prime");
else
printf("not prime");
}
Explanation
We know that any number is divisible by one and itself, that’s why we have avoided
dividing with those two numbers, thereby avoiding two runs.
(Method-3)
void main()
{
int i, n, count = 0;
printf("Enter a number:");
scanf("%d", &n);
if(count == 0)
printf("prime");
else
printf("not prime");
}
Explanation
We know that the factor of a number cannot be greater than half of that number and
hence the code.
(Method-4)
void main()
{
int i, n, flag = 0;
printf("Enter a number:");
scanf("%d", &n);
if( n % i == 0)
{
flag = 1;
break;
}
}
if(flag == 0)
printf("prime");
else
printf("not prime");
}
Explanation
As soon as a factor is encountered (between 2 and n/2), we can stop the iteration, there
is no point in keep on counting the number of factors. To stop the loop we can use
“break” statement. We will it more details in the Jump Statements section.
void main()
{
int n, i, f = 1;
printf("Enter a number:");
scanf("%d", &n);
Output
Enter a number : 5
Factorial : 120
(Method-2)
void main()
{
int n, f = 1;
printf("Enter a number:");
scanf("%d", &n);
while( n )
{
f = f * n;
n--;
}
Explanation
In C language’s point of view, any +ve or –ve value is treated as TRUE whereas 0(zero)
is treated as FALSE. So the while loop runs as long as the value of ‘n’ is non – zero.
(Method-3)
void main()
{
int n, f = 1;
printf("Enter a number:");
scanf("%d", &n);
while( n )
f = f * n--;
Explanation
This method is the most compact one. We know that, if there is only one instruction
associated with a loop, then no need of enclosing it within the braces.
A Program which reads a number and prints that many numbers from the fibonacii
series. Fibonacii series : 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 …
Program 3.18
void main()
{
int n, i, a = 0, b = 1, c;
printf("Enter a number:");
scanf("%d", &n);
printf("%d\t%d\t", a, b);
a = b;
b = c;
}
}
Program 3.19
void main()
{
int i;
i = 1;
while( 1 )
{
printf("%d\t", i);
i++;
}
}
Output
Explanation
We know that ‘i’ can hold a number max of 32767 and a min of -32767. Hence ‘i’ value
oscillates between this range.
There are many advantages of infinite loop, very soon you will understand it.
do – while loop
Syntax
i.c
do
{
statements to be executed
…
…
…
m.c
}while(t. c);
void main()
{
int i;
i = 1;
do
{
printf("%d\n", i);
i++;
Whenever we need to transfer the control from one place to another (distance) place in
a program then we use jump statements.
break
continue
goto
break statement
Example 1
Program 3.21
void main()
{
int n, max = 0;
char ch;
while( 1 )
{
printf("Enter a number:");
scanf("%d", &n);
printf("Another number[y/n]:");
ch = getch();
if(ch != 'y')
break;
}
printf("Maximum : %d", max);
}
Explanation
a) The loop continues as long as the user presses ‘y’. Now you would appreciate the
use of infinite loop.
b) ch = getch();
getch() is an exclusive function for reading a character. Till now you might be using
this just to avoid pressing ALT + F5 to view the output.
getch() reads a character a character and stores it in ‘ch’
Example 2
Program 3.22
void main()
{
int n, i;
if( n % 2 == 0)
break;
}
}
continue statement
When a continue statement is encountered, in a loop, the control skips the execution of
the remaining statements in that loop and continues with the next iteration of the loop.
Example 1
Program 3.23
void main()
{
int i, j;
Output
1, 2
1, 3
2, 1
2, 3
3, 1
3, 2
4, 1
4, 2
4, 3
5, 1
5, 2
5, 3
Example 2
Program 3.24
void main()
{
int i;
printf("%d\t", i);
}
}
Output
It is also called as trinary operator. i.e., it has three operands. Conditional operator can
be used as an alternative form of bi-directional decision control structure.
Form 1
If expr1 is a TRUE value, expr2 gets executed otherwise expr3 gets executed.
Form 2
If expr1 is a TRUE value, the variable gets the value from expr2 otherwise from expr3
Example 1
Program 3.25
void main()
{
int m;
printf("Enter marks:");
scanf("%d",&m);
Example 2
Program 3.26
void main()
{
int a, b, max;
max = ( a > b ) ? a : b;
&& (AND)
|| (OR)
! (NOT)
The result of a logical operation is always either TRUE or FALSE . i.e., 1 (one) or 0
(zero)
It is a binary operator, which takes two operands. The operands can be variables/
constants/expressions.
Truth table
A B A&&B
T T T
T F F
F T F
F F F
So a logical && (AND) operation can be TRUE only if both the operands are TRUE
values.
Example
Program 3.27
void main()
{
int m1, m2, m3;
Explanation
Remember that while performing a logical AND operation, if the left operand is a FALSE
value, the right operand will not be evaluated (Since not required).
It is a binary operator, which takes two operands. The operands can be variables/
constants/ expressions.
Truth table
A B A||B
T T T
T F T
F T T
F F F
So a logical || (OR) operation can be TRUE if at least one of the operands is a TRUE
value.
Example
Program 3.28
void main()
{
char ch;
printf("Enter an alphabet:");
scanf("%c", &ch);
Explanation
Remember that while performing a logical OR operation, if the left operand is a TRUE
value, the right operand will not be evaluated (Since not required).
Note : Logical && and logical || are usually used to join more than one condition.
It is a unary operator, So it takes only one operand. The operand can be variables/
constants/expressions.
Truth table
A !A
T F
F T
If the operand is a TRUE value, it returns FALSE (0), otherwise returns TRUE (1).
Program 3.29
void main()
{
int a = 10, b = -8, c = 0, i, j, k, l;
i = !a;
j = !b;
k = !c;
l = ! ( a == 10);
Output
0, 0, 1, 0
Whenever we need to select an option from a set of options, we use switch- case
control structure.
Syntax
switch ( expr )
{
case constant1 : statements
…
…
…
break;
case constant2 : statements
…
…
…
break;
case constant3 : statements
…
…
…
break;
…
…
…
default : statements
}
First, the expression following the switch – keyword is evaluated. The resultant value is
then matched, one by one, against the constant values that follow the case keywords,
when a match is found the statements associated with that case gets executed and the
control terminates from the entire switch structure (when break is encountered in
between). If a match is not found, the statements associated with the default, gets
executed.
Example 1
Program 3.30
void main()
{
int n;
printf("Enter a number:");
scanf("%d", &n);
switch( n )
{
case 1 : printf("I am in case 1");
break;
case 2 : printf("I am in case 2");
break;
case 3 : printf("I am in case 3");
break;
case 4 : printf("I am in case 4");
break;
case 5 : printf("I am in case 5");
break;
default : printf("I am in default");
}
}
Output
Enter a number: 3
I am in case 3
Example 2
Program 3.31
void main()
{
char ch;
printf("Enter an alphabet:");
scanf("%c", &ch);
switch( ch )
{
case 'c' : printf("Chandigarh");
break;
case 'b' : printf("Baroda");
break;
case 'v' : printf("Vizag");
break;
case 'n' : printf("Nagpur");
break;
default : printf("Guesswhere?");
}
}
void main()
{
char ch;
printf("Enter an alphabet:");
scanf("%c", &ch);
switch( ch )
{
case 'a' :
case 'e' :
case 'i' :
case 'o' :
case 'u' : printf("Vowel");
break;
default : printf("Consonant");
}
}
Example
Here, we are making use of a fact that once a case is satisfied, the control simply falls
through the case till it doesn’t encounter a break statement. So fall through is used,
when in more than once case the task to be done is same.
3.9 goto
goto statement can be used to move the control from one place to another place in a
function.
void main()
{
int i, j, k;
allout:
printf("out of all the nested loops");
}
Explanation
goto statement is usually associated with a label. In our program “allout” is called as
label. A label has the same form as a variable name, & is followed by a colon. It can be
attached to any statement in the same function where goto is present.
Example 2
goto can be used as an alternate to a loop.
Program 3.34
void main()
{
int n, m, i, max = 0;
printf("How many numbers do u want to enter:");
scanf("%d", &n);
i = 0;
readanumber :
printf("Enter a number:");
scanf("%d", &m);
i++;
if( i < n )
goto readanumber;
Explanation
While developing a program, if we use too many gotos (even if the need can be fulfilled
with other control structures, more simpler), maintenance of the program becomes
very difficult. We can never be sure how we got to a certain point in our code. Hence
avoid using goto.
3.10 Comments
Any message within /* and */ is a comment. The contents of a comment are ignored by
the
Compiler (i.e., not Compiled)
Uses
Usually we should not put any semicolon at the end of “for” loop expression. Lets see
what happes if we put a semicolon at the end of a for loop expression.
Program 3.35
void main()
{
int i;
Output
11
Explanation
a) If we put a semicolon at the end of a for loop expression, it means that there is
nothing inside the for loop. So the immediate statement doesn’t belong to the for loop.
b) The for loop runs as long as the condition is TRUE. When the control terminates
the for
loop, ‘i’ would be 11 and hence the output.
Lets see what happens if we put a semicolon at the end of an ‘if’ expression.
Example 1
Program 3.36
void main()
{
int n;
printf("Enter a number:");
scanf("%d", &n);
if( n == 10) ;
printf("The entered number is 10");
}
Output
Enter a number : 15
The entered number is 10
Explanation
Example 2
Program 3.37
void main()
{
int m;
printf("Enter marks:");
scanf("%d", &m);
if( m >= 35 ) ;
printf("Passed");
else Error
printf("Failed");
}
Explanation
As explained in the previous example, there is no statement associated with the ‘if’
expression. So there is no connection between the ‘if’ expression and the
printf(“Passed”); statement.
The Rule is: else part should immediately follow the ‘if’ block, otherwise the else
part/block is called as hanging else which is illegal in C.
Ex1 : In KBC (kaun Banega Crorepathi) game, removing randomly selected two
incorrect answers
(Method-1)
#include<stdlib.h>
void main()
{
int i, r;
randomize();
for(i=1;i<=10;i++)
{
r = random(100);
printf("%d\t", r);
}
Output
Explanation
• random() takes a number and returns a random number in the range 0 to one less
than the given number.
• randomize() initializes the random number generator with a random value.
• However the above library is not portable across all compilers, In the next program
we will see the portable method
(Method-2)
void main()
{
int i, r;
srand(time());
for(i=1;i<=10;i++)
{
r = rand() % 100;
printf("%d\t", r);
}
}
Explanation
a) srand() : It seeds the random number generator used by the function rand(). It
takes an integer value to be used as seed by the pseudo random number generator
algorithm. Often the time() function is used as input for the seed
b) time(): It returns the time since January 1, 1970 in seconds, which, we know
keeps on changing for execution of the program.
• When we know in advance, the number of times the loop should run.
• When we have all the three expression – initialization, testing and modification,
directly.
• When, modification should take place at the end of a loop.
• When the modification expression is small, usually unary incrementation /
decrementation.
While
• When we don’t know in advance, the number of times the loop should run.
• When the modification expression has to occur in between the body of the loop.
• When the initialization and/or modification is/are big expressions
do – while
Similar to while loop, except that it runs atleast once.
Note
Remember that a task that can be performed using one loop, can also be performed
using the other two loops. However a particular loop would be more suitable for a
particular requirement.
for, while loops are called as pre-checking loops, where as do-while loop is called as
post-checking loop.
3.15 C instructions
Till now we have seen several types of instructions. Lets classify them:
3.16 pyramids
1
12
123 if the given number is 5
1234
12345
Program 3.39
void main()
{
int n, i, j;
printf("Enter a number:");
scanf("%d", &n);
/* pyramid - example 2 */
/* A program which reads a number and generates the following pyramid */
1
22
333 if the given number is 5
4444
55555
Program 3.40
void main()
{
int n, i, j;
printf("Enter a number:");
scanf("%d", &n);
for(i = 1 ; i <= n ; i++)
{
for(j = 1 ; j <= i ; j++)
printf("%d", i); /*we know that ‘i’ remains constant inside the ‘j’ loop*/
printf("\n");
}
}
/* pyramid - example 3 */
/* A program which reads a number and generates the following pyramid */
12345
1234
123 if the given number is 5
12
1
Program 3.41
void main()
{
int n, i, j;
printf("Enter a number:");
scanf("%d", &n);
printf("\n");
}
}
/* pyramid - example 4 */
/* A program which reads a number and generates the following pyramid */
54321
4321
321 if the given number is 5
21
1
Program 3.42
void main()
{
int n, i, j;
printf("Enter a number:");
scanf("%d", &n);
printf("\n");
}
}
/* pyramid - example 5 */
/* A program which reads a number and generates the following pyramid */
1
12
123 if the given number is 5
1234
12345
Program 3.43
void main()
{
int n, i, j, k;
printf("Enter a number:");
scanf("%d", &n);
printf("\n");
}
}
/* pyramid - example 6 */
/* A program which reads a number and generates the following pyramid */
1
123
12345 if the given number is 5
1234567
123456789
Program 3.44
void main()
{
int n, i, j, k;
printf("Enter a number:");
scanf("%d", &n);
printf("\n");
}
}
/* pyramid - example 7 */
/* A program which reads a number and generates the following pyramid */
1
12
123 if the given number is 5
1234
12345
1234
123
12
1
Program 3.45
void main()
{
int n, i, j, k;
printf("Enter a number:");
scanf("%d", &n);
printf("\n");
}
}
Exercise
4. ARRAYS
Topic # 4
Atish Jain
Arrays are variables capable of holding more that one value at a time.
For understanding the requirement of arrays lets consider the following two programs:
Program 4.1
void main()
{
int m, i;
Output
Explanation
Ordinary variables are capable of holding only one value at a time. That’s why each
time when we enter a new value into ‘m’, the existing value gets overwritten. So down
the program when we want to access the marks of all the five students, we couldn’t do
so. So certainly this is not the solution for our problem.
void main()
{
int m1, m2, m3, m4, m5;
Output
Explanation
No doubt, this program meets our requirement, but imagine a program which need to
read 300 students’ marks. In such a case we have two options to store these marks in
memory:
i) Define 300 variables to store marks obtained by 300 different students.
ii) Define one variable capable of holding all the 300 marks.
Use of Arrays
Array
Example :
int a[10];
The above statement tells the Compiler to reserve sufficient amount of space to store
10 integers ( 20 bytes) and specify a name ‘a’ to the entire collection.
Size : Denotes the maximum number of elements that can be stored in the array.
elements 26 14 93 6 7 9 13 43 12 54
indices 0 1 2 3 4 5 6 7 8 9
addresses 100 102 104 106 108 110 112 114 116 118
The indices begin with 0 (zero) and ends with one less than the size of the array.
The array elements are accessed or referred to by its position in the group, called index
or subscript.
/* a program which reads a set of integers into a 1-D int array and prints them */
Program 4.3
void main()
{
int a[10], n, i;
printf("Enter numbers:");
for(i = 0 ; i < n ; i++)
scanf("%d",&a[i]);
Output
Explanation
a) Arrays are used only when the maximum size of a collection is known during the
development of the program.
b) When the program is executed, we get the prompt : How many :
Do remember that the number that we enter ( the ‘n’ value) should be less than or
equal to the size of the array.
c) No bounds checking
In ‘C’, there is no check to see if the subscript used for an array exceeds the size of the
array. Data entered with a subscript exceeding the array size will simply be placed in
memory outside the array (i.e., outside the reserved area of that array), probably on
top of other data (reserved or unreserved). This will lead to unpredictable results:
Program 4.4
void main()
{
int a[10], n, i, s = 0;
printf("Enter numbers:");
for(i = 0 ; i < n ; i++)
{
scanf("%d",&a[i]);
s = s + a[i];
}
/* results sheet */
Program 4.5
void main()
{
int rno[10], marks[10], n, i;
printf("Results sheet\n");
printf("-------------\n\n");
printf("First class\n");
printf("Second class\n");
printf("Third class\n");
void main()
{
int a[10], n, i, j, t, flag;
flag = 0;
}
}
if(flag == 1)
break;
}
Output
Explanation
Sorting any data is one of the most regular activities in computing. There are several
sorting techniques. One of them is the bubble sorting technique.
a) The basic idea in this method is to scan the elements from left to right( or top to
bottom) and sinking the elements with large keys (values) towards the right (bottom)
side.
b) As an example, suppose that there are five elements in the array as following:
8 6 5 9 2
then, according to bubble sorting, a total of four passes (repetitions) are carried
out.
c) At the end of pass one, the largest element among the five elements is set at the
last position.
d) At the end of pass two, the largest element among the remaining four elements
is set at the second last position.
8 9
e) Similarly at the end of all the four passes the array would be sorted completely.
2 5 6 8 9
Now the question is how to set the largest element among a set a elements at its
appropriate position?
8 6 5 9 2
6 8 5 9 2
6 5 8 9 2
6 5 8 9 2
6 5 8 2 9
At the end of this pass – one, the element with the largest key value is set at the
last position.
So, for ‘n’ elements (n-1) passes are carried out, and hence the outer for loop is
repeated (n-1) times.
and each time (n-1-i) comparisons are carried out and hence the inner for loop is
repeated (n-1-i) times.
14 8 9 13 17 23 5
0 1 2 3 4 5 6
So when an array is initialized, mentioning its size becomes optional. The Compiler
automatically sets its size with the number of elements initialized.
9 13 7 6 0 0 0 0 0 0
Note that, even if one location is initialized, the remaining locations of the array will be
filled with zeros.
The way a group of integers can be stored in an integer array, similarly, a group of
characters can be stored in a character array. Character arrays are used while dealing
with names. Many a times 1-D character arrays are also called as strings.
char st[20];
The above statement, tells the Compiler to reserve sufficient amount of space to store
20 characters ( 20 bytes) and specify a name ‘st’ to the entire collection.
method 1
char st[ ] = { ‘v’, ‘i’, ‘k’, ‘r’, ‘a’, ‘m’ };
v i k r a m
0 1 2 3 4 5
100 101 102 103 104 105
method 2
7 string constant
v i k r a m \0
0 1 2 3 4 5 6
100 101 102 103 104 105 106
Soon we will discuss the significance of this null character. Even though ‘\0’ seems to
be two characters only one byte is allocated for it. Note that whatever is followed after
\ (backslash) is a special character.
#include<stdio.h>
void main()
{
char st[30];
int n, i;
Explanation
void main()
{
char st[30];
Output
Explanation
b) The %s format specifier in the scanf() function keeps on reading the characters
until it encounters a whitespace character (space/tab space/enter key) and places a
special character called as null character at the end of the string (the null character
indicates end of the string). That’s why no need of loops for reading stings.
c) Note that the %s format specifier in the scanf() can accept only single word (as
the string gets terminated on encountering a whitespace character).
d) The %s format specifier in the printf() function keeps on printing the characters
until it encounters the null character(‘\0’).
void main()
{
char na[30];
printf("Enter a name:");
gets(na);
printf("%s", na);
}
Output
Explanation
a) gets() is an exclusive function for reading strings( it can read multi-word strings
as well).
Also gets() function executes faster than scanf() function because relatively
gets() function has less machine code than the machine code of scanf() function,
because gets() function handles only strings whereas scanf() function can handle any
type of data.
b) There is one more way to read multi-word strings:
stop enter key
scanf(“ %[ ^ \n ] ” , na);
search set
keep on searching for the enter key(‘\n’) from the keyboard buffer area and stop
reading the characters as soon as it is found.
Remember that when we enter any data from the keyboard, the data is initially
stored in the keyboard buffer, when we press the enter key only then the characters
are passed into RAM(because how can the Compiler know where our input value ends).
Note that using puts(), only one string can be printed at a time.
puts(), after printing the string, positions the cursor in the next line.
String handling is very often done in programming. For fulfilling the common
requirements, we have a good collection of library functions. Lets see how to use them.
Program 4.10
void main()
{
char st[30];
int l;
puts("Enter a string:");
gets(st);
l = strlen(st);
/* string copy */
Program 4.11
void main()
{
char st1[30], st2[30];
printf("Enter a string:");
gets(st1);
target string
strcpy(st2, st1);
source string
printf("%s\n%s", st1, st2);
}
Output
/* string reverse */
Program 4.12
void main()
{
char st1[30], st2[30];
printf("Enter a string:");
gets(st1);
strcpy(st2, st1);
strrev(st2);
printf("Original : %s\nReverse : %s", st1, st2);
}
Output
/* string comparision */
Program 4.13
void main()
{
char st1[30], st2[30];
int n;
n = strcmp(st1, st2);
if(n == 0)
printf("same");
else
printf("not same");
}
Output
/* string concatenation */
Program 4.14
void main()
{
char st1[30], st2[30], st3[60];
int n;
strcpy(st3, st1);
strcat(st3, st2);
Output
shiva
rama
shivarama
Even though we have so many string library functions, they cannot fulfill our specific
requirements.
So for that purpose we have to code them. First, lets imitate the above used library
functions.
void main()
{
char st[30];
int i;
puts("Enter a string:");
gets(st);
}
Explanation
a) As you know, semicolon at the end of a for loop statement indicates that there is
nothing inside the for loop. The loop runs as long as the testing condition is TRUE.
b) st[i] != ‘\0’;
We know that a string is terminated by the null character. That’s why we keep
on incrementing ‘i’ until the null character is encountered.
c) When the control comes out of the for loop, ‘i’ contains the length of the string.
Program 4.16
void main()
{
char st1[30], st2[30];
int i;
puts("Enter a string:");
gets(st1);
st2[i] = '\0';
Explanation
• Within the loop the null character doesn’t get copied into the target string.
Hence this job is done explicitly outside the loop.
• ‘\0’ can be represented as 0(zero) which is its ASCII value or NULL (a macro).
To use this macro we have to include the file stdio.h at the top of the program as
follows:
void main()
{
char st1[30], st2[30];
int l, i, j;
puts("Enter a string:");
gets(st1);
j = l - 1;
st2[i] = 0;
void main()
{
char st1[30], st2[30];
int l1, l2, i;
if(l1 != l2)
{
printf("not same");
exit();
}
if(i == l1)
printf("same");
else
printf("not same");
}
Explanation
a) Here the logic is if the lengths are not same, just print the message : “not same”
and quit the program. exit() function is used to terminate the program. Remember that
break is used to terminate a loop, whereas exit() is used to terminate a program.
b) If the lengths are same then run a loop(length number of times) and terminate
the loop as soon as the compared characters are different. Outside the loop just check
whether the loop has run length number of times or not.
void main()
{
char st1[30], st2[30], st3[60];
int i, j;
j = i + 1;
st3[j] = 0;
Output
void main()
{
char st[128];
int i, nwords = 0;
puts("Enter a sentence:");
gets(st);
puts("Enter a sentence:");
gets(st);
A 2-D array is nothing but a collection of 1-D arrays. 2-D arrays are used to represent
any data in rows and col.s format.
int m[5][4];
rows columns
m[0][0] 0 1 2 3
0
1
m[2][2] 2 m[4][3]
3
4
m[4][1]
To access an element of a 2-D int array we have to specify both the row and column
subscripts.
int m[][3] = {
{1, 2, 3},
4 {4, 5, 6},
{7, 8, 9},
{10, 11, 12}
};
Note
Even though the 2-D array elements are represented in a tabular format, they are
internally stored in contiguous (adjacent) memory locations.
int m[5][4];
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
100 102 104 106 108 110 112 114 116 118 120 122 124 126 128 130 132 134 136 138
/* reading/printing a matrix */
Program 4.22
void main()
{
int m[5][5], r, c, i, j;
printf("Enter elements:");
for(i = 0 ; i < r ; i++)
for(j = 0 ; j < c ; j++)
scanf("%d", &m[i][j]);
printf("\n");
}
}
Explanation
a) As we have to access elements in rows and cols, we have used nested loops. The
outer loops runs row number of times, whereas, the inner loop runs column number of
times.
b) During printing the matrix elements, to print each row in each line we have
used printf(“\n”) after the inner loop.
void main()
{
int m[5][5], r, c, i, j, s = 0;
printf("Enter elements:");
for(i = 0 ; i < r ; i++)
for(j = 0 ; j < c ; j++)
{
scanf("%d", &m[i][j]);
s = s + m[i][j];
}
printf("Sum of elements = %d", s);
}
Program 4.24
void main()
{
int m1[5][5], m2[5][5], m3[5][5], r, c, i, j;
printf("\n");
}
}
Explanation
Program 4.25
void main()
{
if(c1 != r2)
{
printf("Multiplication rule violated - cannot be multiplied");
exit();
}
}
}
printf("\n");
}
}
Explanation:
Rule : The number of columns of matrix 1 must be equal to the number of rows of
matrix 2.
How to multiply?
Each row of matrix 1 must be multiplied with each column of matrix 2.
0 1 2 3 0 1 2 3 4 0 1 2 3 4
0 0 0
1 1 1
2 2 2
3
3x4 4x5
3x5
/* coding the product */
}
}
a) To visit every cell of matrix 3 we need two loops ( ‘i’ loop and ‘j’ loop).
b) To fill each cell of m3, we have to carry out the multiplication four times (in our
example). and then add them (running sum). Hence we need another loop which runs
four times (i.e., c1 or r2 times).
Now lets understand,
m1[i][k] * m2[k][j]
We know that,
‘i’ loop runs 3 times
‘j’ loop runs 5 times
‘k’ loop runs 4 times
runs 3 * 5 * 4 = 60 times.
m3 m1 * m2
From the above numbers sequence, it is clear that the 1nd index of m1 changes every
twenty times. We know that ‘i’ changes every twenty times. Hence the code : m[i][k] *
m2[k][j]
/* Transpose of a Matrix */
Program 4.26
void main()
{
int m[5][5], t[5][5], i, j, r, c;
for(i=0;i<r;i++)
for(j=0;j<c;j++)
t[j][i] = m[i][j];
printf("Original Matrix:\n");
for(i=0;i<r;i++)
{
for(j=0;j<c;j++)
printf("%5d", m[i][j]);
printf("\n");
}
printf("\nIts Transpose:\n");
for(i=0;i<c;i++)
{
for(j=0;j<r;j++)
printf("%5d", t[i][j]);
printf("\n");
}
}
Organization in memory
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
0 L a k s h m i \0
1 R a m y a \0
2 J a y a n t h i \0
#include<stdio.h>
void main()
{
char st[10][30];
int n, i;
printf("Enter strings:");
Output
#include<stdio.h>
void main()
{
char st[10][30], t[30];
int n, i, l, max = 0;
printf("Enter strings:");
for(i = 0 ; i < n ; i++)
{
fflush(stdin);
gets(st[i]);
l = strlen(st[i]);
Program 4.29
#include<stdio.h>
void main()
{
char st[10][30], t[30];
int n, i;
printf("Enter strings:");
/* string sorting */
Program 4.30
#include<stdio.h>
void main()
{
char st[10][30], t[30];
int n, i, j, flag;
printf("Enter strings:");
for(i = 0 ; i < n ; i++)
{
fflush(stdin);
gets(st[i]);
}
flag = 0;
}
}
if(flag == 1)
break;
}
Output
Exercise
State true or false
e) Array elements are stored in adjacent locations.
f) Array elements must be of similar datatype.
g) 2-D array elements are stored in adjacent locations.
h) ASCII value of NULL character is zero.
i) gets() can read multi- word strings.
5. Functions
(Basic)
Topic # 5
Atish Jain
Types of functions
Functions
Use of functions
• time is saved
• thereby money is saved
• frustration is saved( because code the same thing again and again leads to
frustration)
• Testing can be avoided (because we use the proved code (already tested) )
Syntax
<return value type> <function name>(parameters list)
{
body of the function
[return <value> ] ; optional
}
5.3 Calling a function
/* calling a function */
Program 5.1
void main()
{
int a, b, c;
c = a + b;
Explanation
Even though we have a huge collection of library functions, they may not meet our
specific requirements. So under these situations we create our own functions and use
them whenever or wherever required.
Program 5.2
void fun()
{
printf("Hello"); function definition
}
void main()
{
fun(); function calling
}
Output
Hello
Explanation
a) Function definition : It contains the function’s return type, name, parameters list
and body.
b) Function calling : Transferring control from one function to another function.
c) Called function : A function which gets called. In our example fun() is the called
function.
d) Calling function : A function which calls an other function. In our example main() is
the
calling function.
e) Note that a function cannot be defined in any other function.
{
int c; formal arguments
c = a + b;
void main()
{
int a, b, c;
c = sum(a, b);
actual arguments
printf("Sum = %d", c);
}
Explanation
a) Actual arguments : The variables used in the function calling statement.
b) Formal arguments : The variables used in the receiving section of the called
function.
c) The name of actual arguments and formal arguments may or may not be same.
Both
of them will have different memory locations.
d) The keyword return is used to return a value from a function.
void main()
{
int a, b, result;
printf("Enter two numbers:");
scanf("%d%d", &a, &b);
result = sum(a, b);
printf("Sum = %d\n", result);
result = diff(a, b);
printf("Difference = %d\n", result);
result = prod(a, b);
printf("Product = %d\n", result);
result = quot(a, b);
printf("Quotient = %d", result);
}
Have a look at the first program of this chapter. Guess what happens if we define the
fun() function below the main() function? Error occurs. Why? To understand the
reason, you should know some points:
a) A program’s execution begins from the opening brace of the main() function and
ends at the closing brace of the main() function.
b) However a program’s compilation begins from the first line of the program and
ends at the last line of the program.
d) Now let’s discuss the error : In this case main() gets compiled first, when the
statement fun(); gets compiled, the compiler assumes that its return type is an
integer(as by that time the compiler doesn’t know about its definition). But down the
program, we have mentioned its return type as void. Hence the compiler reports an
error message.
e) An ideal place to define a function is above its caller (i.e., its calling function).
Conclusion
If a function’s return type is an integer then it can be defined any where (above or
below its caller).
However if we want to define a non-integer return type function, below its calling
function, then we have to provide the called function’s prototype (here fun() ‘s) in its
calling function (here main() ) at the place where we define the variables.
void main()
{
void fun(); function prototype/declaration
fun();
}
void fun()
{
printf("Hello");
}
Note
The ideal place to specify a function’s prototype is outside and above all the functions,
so that it can be called by any other function of the program.
Program 5.6
int fact(int n)
{
int f = 1;
if(n > 7)
{
printf("Sorry! can't find a factorial for a number > 7");
return -1;
}
while( n )
f = f * n--;
return f;
}
int reverse(int n)
{
int r, rev = 0;
while( n )
{
r = n % 10;
rev = rev * 10 + r;
n = n / 10;
}
return rev;
}
void prime(int n)
{
int i, flag = 1;
for(i=2; i<=n/2;i++)
if(n%i == 0)
{
flag = 0;
break;
}
if(flag == 1)
printf("prime");
else
printf("not prime");
}
void armstrong(int n)
{
int r, s = 0, t;
t = n;
while( n )
{
r = n % 10;
s = s + r * r * r;
n = n / 10;
}
if(t == s)
printf("armstrong");
else
printf("no");
}
void main()
{
char ch;
int n1, n2;
printf("Enter a number:");
scanf("%d", &n1);
while( 1 )
{
printf("1.Factorial\n");
printf("2.Reverse\n");
printf("3.Prime\n");
printf("4.Armstrong\n");
printf("5.Exit\n\n");
In the previous program, you have created four different functions and used it that
program.
Suppose that, in a different program, you again require all these (or some) functions,
what would you do? copy and paste in the new program? No. Instead it would be nice
to separate those user- defined functions and save in a separate file and use them in all
the programs which requires them (all or some). Let’s see how this can be achieved.
/* header- file which consists of fact(), reverse(), armstrong() and prime() functions
definitions */
Program 5.7
int fact(int n)
{
int f = 1;
if(n > 7)
{
printf("Sorry! can't find a factorial for a number > 7");
return -1;
}
while( n )
f = f * n--;
return f;
}
int reverse(int n)
{
int r, rev = 0;
while( n )
{
r = n % 10;
rev = rev * 10 + r;
n = n / 10;
}
return rev;
}
void prime(int n)
{
int i, flag = 1;
for(i=2; i<=n/2;i++)
if(n%i == 0)
{
flag = 0;
break;
}
if(flag == 1)
printf("prime");
else
printf("not prime");
}
void armstrong(int n)
{
int r, s = 0, t;
t = n;
while( n )
{
r = n % 10;
s = s + r * r * r;
n = n / 10;
}
if(t == s)
printf("armstrong");
else
printf("no");
}
step2
printf("Enter a number:");
scanf("%d", &n1);
while( 1 )
{
printf("1.Factorial\n");
printf("2.Reverse\n");
printf("3.Prime\n");
printf("4.Armstrong\n");
printf("5.Exit\n\n");
Explanation
In the statement:
#include"myfuns.h"
Note that we have used double quotations instead of the conventional angular brackets.
Why is this discrimination for our header file?
Exercise
6. Macros and
Storages Classes
1.
Topic # 6
Atish Jain
#include directive
#define directive
#include directive
You are already aware of this directive. We have used this whenever we required to
include any file.
Eg : #include<stdio.h>
#include<conio.h>
#include<myfuns.h>
Whenever the preprocessor encounters this directive, it inserts the specified file in the
current file.
#define directive
Note that the preprocessor directives are not ‘C’ language instructions. They are
replaced by an appropriate ‘C’ code.
6.2 Macros
Defining a macro
Syntax
#define < macro template > < macro expansion >
/* macros - example 1 */
Program 6.1
#define NULL 0
void main()
{
char st[20];
int i;
puts("Enter a string:");
gets(st);
for(i=0; st[i] != NULL ; i++);
printf("Length = %d", i);
}
Explanation
a) Here we have defined a word NULL as 0 (zero). So in our program, where ever there
is NULL, it is replaced by 0 (zero). Isn’t NULL more readable than 0 (zero)?.
/* macros - example 2 */
Program 6.2
#define TRUE 1
void main()
{
while( TRUE )
{
printf("This loop runs infinite times\n");
}
}
/* macros - example 3 */
Program 6.3
#define PI 3.142857
void main()
{
float r, a;
a = PI * r * r;
Note
It is just customary to use capital letters for a macro template. This makes it easy for
the programmer to identify all the macros while reading through the program. Usually
variable names and function names are defined in lowercase, whereas, macros are
defined in uppercase.
A macro expansion can extend more than one line, except for the last line, there should
be a backslash ( \ ) at the end of every line.
The macros that we have seen so far are called as simple macros. Macros can have
arguments, just as functions can.
Explanation
In the above example, a macro was used to find the sum of two integers. As we know,
even a function can be written to do this job. Then why have we used a macro?
Here, the preprocessor replaces the macro template with its expansion. i.e., SUM(a,b) in
the printf() is replaced by a+b . So there is no such thing as macro call during
execution. Usually macros makes the program execute faster but increases the program
size (if macro expansion is a big one), whereas functions make the program slower but
smaller and compact.
void main()
{
float r, a;
printf("Enter radius of a circle:");
scanf("%f", &r);
a = AREA(r);
printf("Area of the circle = %f", a);
}
#include<math.h>
#define MAC(x, y) sqrt(x*x + y*y)
float fun(int x, int y)
{
return sqrt(x*x + y*y);
}
void main()
{
int a = 3, b = 4;
float p, q, r, s;
p = fun(a, b);
q = fun(a+1, b+1);
r = MAC(a, b);
s = MAC(a+1, b+1);
printf("Using functions : %f, %f\n", p, q);
printf("Using macros : %f, %f", r, s);
}
Output
Using functions : 5.000000, 6.403124
Using macros : 5.000000, 4.000000
Explanation
Surprised? As you have observed, the values of ‘q’ and ‘s’ are different but we have
expected them to be same.
Macros employs blind replacement strategy. i.e.,
s = MAC(a+1, b+1);
will be replaced by
s = sqrt(a+1*a+1 + b+1*b+1);
which leads to, s = sqrt( a + a + 1 + b + b + 1)
Hence it is always safe to enclose the variables in the macro expansion within
parenthesis.
i.e., #define MAC(x, y) sqrt((x)*(x) + (y)*(y))
Had we used this style, ‘q’ and ‘s’ would have been same.
Till now, while defining a variable we mentioned only its data type. Even though we
haven’t mentioned anything more than that, something is assumed by default. To fully
define a variable we need to mention not only its data type , but also its storage class. If
we don’t specify the storage class of a variable in its definition, the Compiler will
assume a default storage class depending on the context where the variable is defined.
• auto (automatic)
• static
• register (CPU register)
• extern (external)
Default initial value: What will be the default initial value of the variable as
soon as it is defined.
Location: Where the variable would be stored.
Scope: Where the variable can be accessed.
Life: How long the memory remains reserved for the variable.
/* nameless blocks */
Program 6.7
void main()
{
int a = 10;
printf("%d\n", a);
{
printf("St Anns School - Secunderabad");
}
}
Output
10
St Anns School - Secunderabad
Explanation
In ‘C’, nameless blocks are possible within a function block. The use is memory can be
conserved.
void main()
{
int a = 10;
printf("%d\n", a);
{
int b = 20;
printf("%d", b);
}
}
Explanation
In ‘C’ a variable must be defined before the first executable statement in a block.
/* where can we access a variable */
Program 6.9
void main()
{
int a = 10;
printf("%d\n", a);
{
int b = 20;
printf("%d, %d\n", a, b);
}
Explanation
A variable defined in a block can be accessed in that block and all its inner blocks (i.e., a
variable defined in a block cannot be accessed in its outer block). It is called as the
scope of a variable.
Program 6.10
void fun()
{
int a = 10;
printf("%d\n", a);
a++;
}
void main()
{
fun();
fun();
fun();
}
Output
10
10
10
Explanation
Whenever the control comes out of the fun() functions’ block, the variable ‘a’ dies. i.e.,
memory allocated to ‘a’ gets unreserved, and hence the output.
void fun()
{
static int a = 10;
printf("%d\n", a);
a++;
}
void main()
{
fun();
fun();
fun();
}
Output
10
11
12
Explanation
a) We know that static variable’s life is as long as the program is under execution.
b) static and global (very soon you will understand its meaning) variables are also
called as load time variables. i.e., for these variables memory gets allocated as soon as
the program gets loaded into memory( before the execution of main() function ) and
memory gets de-allocated just before the termination of the program from the memory.
c) Remember that, the statement,
gets executed only once. So, no matter how many times the control enters the fun()
functions’ block, only once this statement gets executed and rest of the times it gets
ignored. Also remember that the latest value of the static variable persists (remains
undestroyed) between different function calls, and hence the output.
The register storage class specifier indicates to the Compiler that the value of the
variable should reside in a machine register (CPUs memory area). The Compiler is not
required to honor this request. Because of the limited size and number of registers
available on most systems, few variables can actually be put in registers. If the
Compiler does not allocate a machine register for a register variable, the variable is
treated as having the storage class specifier auto. A register storage class specifier
indicates that the variable, such as a loop control variable, is heavily used and that the
programmer hopes to enhance performance by minimizing access time (register
accessing is faster than RAM accessing).
To understand this concept better, just consider the following example:
Cooking becomes faster if all the food items are put near to the stove, rather than at a
distance place
in the kitchen.
void main()
{
register int i;
for(i=1;i<=100;i++)
printf("I Love India\n");
}
Explanation
We know that here, ‘i’ gets accessed around 300 times. So, if it is made to reside in the
CPU registers, program execution would be faster.
Remember that, we cannot use register storage class for all types of variables.
Eg:
register long a;
register float b; all are illegal
register double c;
This is because the CPU registers in a microcomputer are usually 16-bit registers,
therefore cannot hold a float value or a double value. The Compiler would treat the
variables to be auto storage class.
A limitation of register variables is that you cannot apply address of (&) operator. This
is because the CPU registers do not have memory addresses.
/* global variables */
Program 6.13
int i = 78;
void fun1()
{
printf("%d\n", i);
}
void fun2()
{
int i = 45;
printf("%d\n", i);
}
void main()
{
printf("%d\n", i);
fun1();
fun2();
}
Explanation
The variables, which are required in more than one function, are defined globally i.e.,
outside and above all the functions.
Use
Usually a big program is divided into a number of files, so that maintenance of the
program becomes easy. A variable defined in a file can be accessed by other files as
well, such a variable is called as extern (external) variable.
Step 1 : Create a file f1.h and just define a variable in this file.
/* external variable */
#include"f1.h"
void main()
{
extern int i; /*variable declaration (memory is not allocated)*/
printf("%d", i);
}
Explanation
The statement,
extern int i;
indicates that the variable ‘i’ is defined externally in a separate file( sometimes in the
same file but outside and below that function where this statement is present)
When to use what?
Linking ( by linker)
Result
Exercise
7. Pointers &
Advanced
Functions
1.
Topic # 7
Atish Jain
After going through this chapter you will surely appreciate the use of pointers.
There are many issues to be discussed. Let’s begin our journey with how to print an
address.
void main()
{
int a = 10;
printf("%d\n", a);
printf("%u", &a);
}
Output
10
65494
Explanation
a) We know that every variable has an address. If we want, we can know what
address is assigned to a variable (by the compiler).
b) To print the address of an integer variable just use &a in the printf() function
c) %u In a 16-bit compiler like Turbo C, a variable can be assigned an address in the
range of 1 to 65535. The maximum positive value that can be printed using %d is
32767. Hence we use %u for printing the addresses of variables. Note that address is
always a positive value.
p = &a;
420 222
a p
222 444
Program 7.2
void main()
{
int a = 35;
int* p;
p = &a;
printf("%u\n", a);
printf("%u\n", &a);
printf("%u\n", p);
printf("%u\n", &p);
printf("%u", *p);
}
Output
35
222
222
444
35
Explanation
b)
35 222
a p
222 444
void main()
{
int a = 35;
int* p;
int** q;
p = &a;
q = &p;
printf("%u\n", p);
printf("%u\n", q);
printf("%u\n", *q);
printf("%u\n", *p);
/* printf("%u\n", *a); illegal */
printf("%u\n", **q);
/* printf("%u\n", **p); illegal */
printf("%u", *&p);
Output
222
444
222
35
35
222
Explanation
a)
35 222 444
a p q
222 444 666
/* size of a pointer */
Program 7.4
void main()
{
int a = 10;
char ch = 'x';
float f = 9.7;
int* p = &a;
char* q = &ch;
float* r = &f;
Output
2, 1, 4
2, 2, 2
Explanation
What ever may be the type of a pointer, only two bytes ( if 16 – bit compiler ) are
allocated as it is going to store an address of a variable When you execute this program
in C-Free Compiler you get pointer size as 4 bytes because it is 32-bit compiler.
7.6 Why different types for pointers?
Program 7.5
void main()
{
int a = 4873;
char ch = 'p';
float f = 2173.964;
int* p;
p = &a;
printf("%u\n", *p); /* dereferencing */
p = &ch;
printf("%u\n", *p); /* dereferencing */
p = &f;
printf("%u", *p); /* dereferencing */
}
Output
4873
garbage
garbage
Explanation
While de-referencing, the compiler can know from how many bytes a value should be
extracted by looking at the pointer type.
Program 7.6
void main()
{
int a = 15;
char ch = 'x';
float f = 9.7;
int* p = &a;
char* q = &ch;
float* r = &f;
Output
Explanation
When a pointer is incremented it moves to the next location of its type. So,
When an integer pointer is incremented , the change is +2
When a character pointer is incremented , the change is +1
When a float pointer is incremented , the change is +4
You will appreciate this logic in dynamic memory management.
/* pointer arithmetic - example 2 */
Program 7.7
void main()
{
int a = 10, b = 20;
int* p = &a, *q = &b;
printf("%u\n", p + 2);
printf("%u\n", p - 2);
/* printf("%u\n", p * 2); illegal */
printf("%u\n", q - p);
/* printf("%u", p + q); illegal */
}
Output
65498, 65500
65502
65494
1
Explanation
10 20 65498 65500
a b p q
65498 65500 65502 65504
Remaining arithmetic is not possible because it would not make any sense (eg : adding
two addresses is meaningless).
Call by value
Call by address/reference
Call by value
/* call by value */
Program 7.8
t = a;
a = b;
b = t;
}
void main()
{
int a = 10, b = 20;
Output
Explanation
Surprised?
swap()
20 10 20 10 10
a b t
666 888 999
main()
10 20
a b
222 444
So the changes made to a and b in the swap() function has no affect on a and b of
main().
Call by address/reference
t = *a;
*a = *b;
*b = t;
}
void main()
{
int a = 10, b = 20;
Output
Explanation
Even now the a, b, in main() and swap() functions are different, but still swapping is
possible.
Let’s see how.
swap()
222 444 10
a b t
666 888 999
main()
20 10 20 10
a b
222 444
So through call by address we can change the values of actual arguments by de-
referencing the formal arguments.
void changeMe(int* a)
{
*a = 72;
}
void main()
{
int a = 145;
Output
Before : 145
After : 72
then what is a?
Name of an array is nothing but the address of its first element. i.e., a is 100
Conclusion
a[ i ] *(a + i)
& a[ i ] (a + i )
/* using arrays */
Program 7.11
void main()
{
int a[100], n, i;
printf("Enter numbers:");
for(i = 0 ; i < n ; i++ )
scanf("%d", &a[i]);
Explanation
a) Suppose that, during runtime, the requirement is only 20 integers, then the
memory allocated for the other 80 integers gets wasted.
b) Suppose that, during runtime, the requirement is 115 integers, then we cannot
change the size of the array.
So there is no flexibility in arrays. Arrays are used only when we know in advance (at
the time of program development) the approximate size of the array. If we don’t know
its( the collection ) size in advance we go for dynamic memory management(DMM).
Using DMM exact amount of memory can be allocated. Let’s see how this can be
achieved.
void main()
{
int* a, n, i;
a = (int*)malloc( n * sizeof(int) );
printf("Enter numbers:");
for(i = 0 ; i < n ; i++ )
scanf("%d", a + i );
free(a);
}
Explanation
a) malloc() is a library function which allocates specified amount of memory from the
heap and returns the base address(starting address) of the allocated memory. Heap is
a dynamically allocated area of memory where the program runs.
b) a = (int*)malloc( n * sizeof(int) );
typecasting
c) Can’t we use 2 in place of sizeof(int) ? We can, but then the program will not be
portable to higher – bit compilers where an integer occupies 4 bytes ( 32- bit
compilers)
a = (int*)calloc(n, sizeof(int));
Difference
calloc() function :
i) takes two arguments
ii) initializes the reserved memory with zeros
e) free()
We know that when a variable goes out of its scope memory allocated for that variable
is automatically de-allocated by the compiler. However dynamically allocated memory
remains allocated as long as the program is under execution. Hence when its need is
over we have to explicitly de-allocate it( otherwise it could lead to memory leaks( very
soon we will discuss this)) so that this memory can to be re used for some other
purpose. To accomplish this job, we use free() function which de-allocates the
dynamically allocated memory. Assume a situation where there are many instructions
to be executed, then you will appreciate the need of freeing the memory.
void main()
{
int* a, n, i, *b;
a = (int*)malloc( n * sizeof(int) );
printf("Enter numbers:");
for(i = 0 ; i < n ; i++ )
scanf("%d", a + i );
free(a);
b = (int*)malloc( n * sizeof(int) );
printf("Enter numbers:");
for(i = 0 ; i < n ; i++ )
scanf("%d", b + i );
Output
4 [3468]
5 [3470]
Note that when we use free() there is a chance that the same memory will be
reused(which can be observed in the second case).
/* use of realloc */
Program 7.14
void main()
{
int* a, n, i, m;
a = (int*)malloc( n * sizeof(int) );
printf("Enter numbers:");
for(i = 0 ; i < n ; i++ )
scanf("%d", a + i );
/* --------------------------------------------------- */
Explanation
At times we may need to adjust the size of the allocated block (allocated using malloc()
or calloc() ). Then we use the library function realloc().
realloc() function adjusts the size of the allocated block to the specified new size and
returns the address of the reallocated block, which might be different than the address
of the original block If the base address of the newly allocated block is different than
the existing base address (returned by the malloc() function) then the realloc()
function automatically copies the existing contents to the new location.
SMA DMA
Array elements can be passed to a function in several ways. Let’s discuss one by one.
void fun(int x)
{
printf("%d\t", x);
}
void main()
{
int a[ ] = {9, 43, 2, 6, 3}, i;
Explanation
Here, we are passing an individual array element at a time to the function fun() and
getting it printed in the fun() function.
This method is not an efficient one because the fun() function gets called five times and
each time the control has to be passed to the fun() function and return to the main()
function. So a lot of time gets wasted.
void main()
{
int a[ ] = {9, 43, 2, 6, 3}, i;
Explanation
Here we have passed all the array elements at once into the fun() function. In this
method we have avoided the wastage of time by calling the function only once. But
imagine an array of 300 elements, is it not difficult to pass the information in this
fashion. Hence this method too is not an appropriate one.
void main()
{
int a[ ] = {9, 43, 2, 6, 3}, i;
fun(a, 5);
}
Explanation
To get the good of both methods, we pass the entire array by passing the base address
of the array and a number representing the total number of elements. This method is
efficient and easy to use as well.
We can return only one value from a function. However, indirectly we can return more
than one value from a function. There are three methods:
for(i=0;i<n;i++)
{
sum += a[i];
b[0] = sum;
b[1] = max;
b[2] = min;
}
void main()
{
int a[ ] = { 24, 62, 875, 21, 75}, b[3];
more(a, 5, b);
Explanation
main()
1057 875 21
24 62 875 21 75
gar gar gar
a 100 102 104 10 108 b
6 200 202 204
swap()
int a[] is nothing but another way of representing int* a. int b[] is nothing but another
way of representing int* b
100 200
a b
b[0] = sum; is same as *(b+0) = sum; is same as value at 200 = 1057
b[1] = max; is same as *(b+1) = max; is same as value at 202 = 875
b[2] = min; is same as *(b+2) = min; is same as value at 204 = 21
*x = sum;
*y = max;
*z = min;
}
void main()
{
int a[ ] = { 24, 62, 875, 21, 75}, x, y, z;
for(i=0;i<n;i++)
{
sum += a[i];
m = (int*)malloc( 3 * sizeof(int) );
*(m + 0) = sum;
*(m + 1) = max;
*(m + 2) = min;
return m;
}
void main()
{
int a[ ] = { 24, 62, 875, 21, 75}, *p;
p = more(a, 5);
free(p);
}
Explanation
m = (int*)malloc( 3 * sizeof(int) );
It is a pointer to a memory location that is freed. In short, we can say object destroyed,
path present.
Dangling pointers in programming are pointers whose objects have since been deleted
or de-allocated, without modifying the value of the pointer.
Using a dangling pointer under the assumption that the object it points to is still valid
can cause unpredictable behavior. The use of dangling pointer can also result in the
silent corruption of unrelated data.
To avoid bugs (logical errors) of this kind, one common programming technique is to
set pointers to the NULL (0) pointer. When the NULL pointer is de-referenced/freed
there is no potential for data corruption or unpredictable behavior.
Note that de-referencing a NULL pointer is compiler dependent. Most of the Compilers
terminate the program on de-referencing a NULL pointer.
{
int x = 10;
p = &x;
}
printf("%d", *p);
}
Output
May not be 10
Explanation
We know that the ‘x’ dies as soon as the control comes out of the inner block, but still
‘p’ points to ‘x’. Hence ‘p’ is called as dangling pointer.
int* fun()
{
int a = 7214; /* use static to avoid dangling pointer */
return &a; /* returning the address of a local auto variable leads to dangling
pointer */
}
void main()
{
int *p;
p = fun();
printf("some piece of code\n");
printf("%d", *p);
}
Output
Explanation
We know that ‘a’ dies as soon as the control comes out of the fun() function, but ‘p’
points to ‘a’.
Hence ‘p’ is called as dangling pointer.
Program 7.23
#define NULL 0
int* fun()
{
int* a, n, i;
a = (int*)malloc( n * sizeof(int) );
printf("Enter numbers:");
for(i = 0 ; i < n ; i++ )
scanf("%d", a + i );
return a;
}
void main()
{
int *b, n , i;
b = fun();
printf("Enter numbers:");
for(i = 0 ; i < n ; i++ )
scanf("%d", b + i ); /* overwriting into unreserved area [ may be disastrous ]
*/
Output
Some output…
Null pointer assignment
Explanation
a) Had we not used a = NULL; , ‘b’ would have still pointed to the de-allocated
location,
which would have further lead to overwriting into unreserved area.
Memory leak
It is a situation where allocated memory is not freed although it is never used again. In
short, we can say object present, path destroyed.
a = (int*)malloc( n * sizeof(int) );
printf("Enter numbers:");
printf("%d\n", *a);
printf("Elements are\n");
Explanation
a = (int*)malloc( n * sizeof(int) );
100 1 2 3 4 5 536
a 100 102 104 106 108 b
As soon as the statement a = &b; gets executed, address of ‘b’ gets stored in ‘a’
536 100
a
As the circled block is dynamically allocated memory, it persists as long the program is
under execution. Since ‘a’ holds 536 there is no way to de-allocate the dynamically
allocated memory, resulting in memory leak.
To avoid memory leak, we should say free(a); just before changing the value of ‘a’.
Explanation
As st2’s original value is lost, it would result in memory leak.
Program 7.26
#define NULL 0
void fun3()
{
int* a, n, i;
void fun2()
{
/* some code here */
fun3();
/* some code here */
}
void fun1()
{
/* some code here */
fun2();
/* some code here */
}
void main()
{
/* some code here */
fun1();
/* some code here */
}
Explanation
Even though the dynamically allocated memory can be used only in the fun() function,
this memory persists as long as the program is under execution, resulting in memory
leak.
To avoid memory leak, we should say free(a), somewhere in the fun() function when it
is no more required.
7.14 Recurrsion
/* meaningless recurrsion */
Program 7.27
void fun()
{
printf("Hello\t");
fun();
}
void main()
{
fun();
}
Output
Hello
Hello
Hello
…
Explanation
The fun() function gets executed infinite times. If the fun() function consists some local
data the program will go out of memory, because at some stage the memory would get
exhausted (because the local data of a function block dies only after the complete
execution of the function). So this type of recursion is useless and dangerous. Useful
recursion is demonstrated in the following programs.
/* recurrsion - example 1 */
/* factorial of a number*/’
Program 7.28
int fact(int n)
{
if( n <= 1) base case
return 1;
return n * fact(n-1); recursive case
}
void main()
{
int n, f;
printf("Enter a number : ");
scanf("%d", &n);
f = fact(n);
printf("Factorial = %d", f);
}
Explanation- Analysis
a) For every recursive function the following two properties must be satisfied:
There must be a base criteria for which the function doesn’t call itself. Each time the
function calls itself(recursion) it must be closer to the base criteria.
b) For each function call separate stacks will be created which contains the local data,
return pointer(calling functions address, so that control can return back to its caller) of
the function. In our program as there are four fun() function calls four different stacks
will be created, they will be destroyed as soon as the control returns to their respective
calling functions.
/* recurrsion - example 2 */
/* binary equivalent of a decimal number */
Program 7.29
void binary(int n)
{
if( n/2 )
binary( n/2 );
printf("%d\t", n % 2);
}
void main()
{
int n;
binary( n );
}
Explanation
Analysis
binary(25)
25%2 will be printed(i.e., 1)
binary(12)
12%2 will be printed(i.e., 0)
binary(6)
6%2 will be printed(i.e., 0)
binary(3)
3%2 will be printed(i.e., 1)
binary(1)
➔ 1%2 will be printed(i.e., 1)
Note that the printf() statement will be executed in the reverse direction of function
call sequence.
/* recurrsion - example 3 */
/* sum of array elements */
Program 7.30
printf("How many:");
scanf("%d", &n);
for(i=0;i<n;i++)
scanf("%d", &a[i]);
s = sumOfArrayElements(a, n);
printf("Sum = %d", s);
}
/* recurrsion - example 4 */
/* nth fibonacci number */
Program 7.31
int fib(int n)
{
if(n == 0 || n == 1)
return n;
void main()
{
int n1, n2;
printf("Enter a number:");
scanf("%d", &n1);
n2 = fib(n1);
printf("nth fibonacci number is : %d", n2);
}
Explanation
Note that first the left function call gets executed and then the right function call gets
executed.
Analysis
n2 = fib(7);
fib(5) + fib(6)
Advantages of recursion
Disadvantages of recursion
void main()
{
int a = 10, b = 20, c = 30, d = 40, i;
int* p[4];
p[0] = &a;
p[1] = &b;
p[2] = &c;
p[3] = &d;
Output
10 20 30 40
Output
Panasonic
Samsung
Philips
LG
Sony
Explanation
The important advantage of the pointer array is that the rows of the array may be of
different lengths.
P a n a s o n i c \0
100 101 102 103 104 105 106 107 108 109
S a m s u n g \0
200 201 202 203 204 205 206 207
P h i l i p s \0
300 301 302 303 304 305 306 307
L G \0
400 401 402
S o n y \0
500 501 502 503 504
elec
100 200 300 400 500
Program 7.34
void main()
{
int *m[10], r, c, i, j;
/* memory allocation */
printf("\n");
}
/* memory de-allocation */
for(i=0;i<r;i++)
free(m[i]);
}
Explanation
Let’s consider the following two cases:
case i)
int m[10][10];
Conclusion
Total memory allocated : 200 bytes
Total memory utilized : 24 bytes
Total memory wasted : 186 bytes
case ii)
int* m[10];
We know that 20 (10 * 2) bytes gets reserved for ‘m’.
During execution, say, r = 3 and c = 4 then another 24 (12 * 2) bytes gets reserved (for
storing the matrix elements).
Let’s understand the statement : scanf("%d", m[i] + j);
We know that to the scanf() we have to specify the addresses of the memory locations
where the values have to be placed.
Conclusion
Finally all the dynamically allocated memory is de- allocated using the free() function.
Using pointer to a pointer, least amount of memory can be wasted while dealing with
matrices.
/* pointer to a pointer */
/* Dynamic memory management for a matrix */
Program 7.35
void main()
{
int **m, r, c, i, j;
/* memory allocation */
m = (int**)malloc( r * sizeof(int) );
/* memory allocation */
or m[i]
printf("\n");
}
/* memory de-allocation */
for(i=0;i<r;i++)
free(m[i]);
/* memory de-allocation */
free(m);
}
Explanation
int** m;
Conclusion
Total memory allocated : 32 (2 + 6 + 24) bytes
Total memory utilized : 24 bytes
Total memory wasted : 8 bytes
]
Even these 8 (2 + 6 (3 * 2)) bytes have been utilized indirectly.
So, actual wastage: 0 bytes only
Finally all the dynamically allocated memory is de- allocated using the free() function.
void main()
{
int a = 10, b = 20;
int *p;
p = &a;
*p = 56; /* valid */
p = &b; /* valid */
Explanation
void main()
{
int a = 10, b = 20;
const int *p;
p = &a;
*p = 56; /* invalid */
p = &b; /* valid */
Explanation
*p cannot be changed
p can be changed
*p = 56; /* valid */
p = &b; /* invalid */
Explanation
*p can be changed
p cannot be changed
void main()
{
int a = 10, b = 20;
const int* const p = &a;
*p = 56; /* invalid */
p = &b; /* invalid */
Explanation
*p cannot be changed
p cannot be changed
7.18 void pointer
/* void pointers */
Program 7.40
void main()
{
int a = 423;
char ch = 'm';
float f = 12.5;
void* p;
printf("%d\n", sizeof(p) );
p = &a;
printf("%d\n", *( int* )p); /* extracts data from two bytes */
p = &ch;
printf("%c\n", *( char* )p); /* extracts data from one byte */
p = &f;
printf("%f\n", *( float* )p); /* extracts data from four bytes */
}
Explanation
We know that every variable (except a register variable) has an address in RAM, and
also we can store that address in a pointer variable. Similarly every function has an
address in RAM, and also we can store that address. To store an address of a function,
we have to use a function pointer. Let’s begin with printing the addresses of functions.
void fun1()
{
printf("Ameerpet\n");
}
void fun2()
{
printf("KPHB\n");
}
void fun3()
{
printf("Gachibowli\n");
}
void main()
{
printf("%u\n", main);
printf("%u\n", fun1);
printf("%u\n", fun2);
printf("%u\n", fun3);
}
Output
545
506
519
532
Explanation
Note that to obtain the address of a function we just have to mention the name of the
function, as has been done in the printf() function above. This is similar to mentioning
the name of an array to get its base address.
void fun()
{
printf("I am fun\n");
}
void main()
{
void (*fp)();
fp = fun;
fp();
}
Output
I am fun
Explanation
a) void (*fp)();
this is the way we define a function pointer. It means, that fp is a function pointer,
which can hold an address of a function whose return type is void and which doesn’t
take any arguments.
b) Why is fp enclosed in parenthesis?
void* fp();
doesn’t it look like a function prototype? where void* is the return type, and fp is the
name of the function. Hence parentheses are required while defining a function
pointer.
c) fp = fun;
The above statement assigns the address of fun() function to the function pointer fp.
fp(); or (*fp)();
void main()
{
float (*fp)(float, float);
float x;
fp = sum;
x = fp(2.4, 1.1);
printf("%f", x);
}
Explanation
fp is a function pointer which is capable of holding an address of a function whose
return type is float and which takes two float type of arguments.
void fun1()
{
printf("Sunami 2004 December\n");
}
void fun2()
{
printf("Vizag HudHud Cyclone 2014 October\n");
}
void fun3()
{
printf("Chennai Rains 2015 November\n");
}
void main()
{
void (*fp[3])() = {fun1, fun2, fun3};
int i;
As we have array of integers, array of integer pointer, we can have array of function
pointers as well. An array of function pointers is nothing but a collection of similar type
of functions (same return type and same type of argument list)
void main()
{
int a, b;
Explanation
a) A function can be nested, provided it’s return type is other than void type.
b) The inner functions get executed first in the direction of left to right.
Program 7.46
#include<stdio.h>
char* getString()
{
char st1[100], *p;
printf("Enter a string:");
fflush(stdin);
gets(st1);
p = (char*)malloc( strlen(st1) + 1 );
strcpy(p, st1);
return p;
}
void main()
{
char* st[10];
int n, i;
Output
Explanation
Even though 100 bytes gets allocated for st1, we know that st1 dies as soon as the
control returns from the getString() function. However the dynamically allocated
memory for each of the strings persists as long as the program is under execution. So
we were able to allocate only required amount of memory for each of the strings.
Very often we have been using the scanf() function. Let’s discuss it in detail…
/* scanf() revisited */
Program 7.47
void main()
{
int n;
char st[20];
printf("Enter a number:");
scanf("%d", &n); /* call by address */
printf("Enter a string:");
scanf("%s", st); /* call by address */
printf("%d\n%s", n, st);
}
Explanation
b) While reading strings, why ampersand(&) is not required in the scanf() function?
We know that name of the array (st) is nothing but an address (base address), so
inherently it is call by address. Hence ampersand (&) is not required for reading the
strings.
Program 7.48
void main()
{
int a[] = {13, 9, 64, 53, 18}, i;
int* p;
p = a;
for(i=0;i<5;i++)
{
printf("%d\t", *p);
p++;
}
printf("\n");
for(i=0;i<5;i++)
{
printf("%d\t", *a);
a++; error
}
}
Explanation
Array is a constant pointer. We know that name of an array contains its base address.
This value cannot be changed.
Use of pointers
Note
Pointers are a fundamental part of ‘C’. If you cannot use pointers properly then you
have basically lost all the power and flexibility that ‘C’ allows. The secret to ‘C’ is in its
use of pointers.
‘C’ is unusual in that it allows pointer to point to anything. Pointers are sharp tools, and
like any such tool, used well they can be delightfully productive but used badly they
can do great damage.
Lot’s of new programmers think they hate pointers. Don’t hate pointers. Love pointers.
Pointers are the difference between having someone’s address written down in a
notebook and carrying their house around with you wherever you go.
Exercise
8. Structures
1.
Topic # 8
Atish Jain
We know that array is a collection of elements of similar type. However, many a times
we need to group multiple types of data into a single entity. To meet this type of
requirement we use structures.
struct book
{
int bno;
char title[20]; elements/fields of the structure
float price;
structure
template
};
struct book b;
Number of bytes allocated for a structure variable is the total amount of memory
required for all its elements. So here ‘b’ occupies 26 ( 2 + 20 + 4) bytes.
Note that memory is allocated for a structure only after defining a variable of its type,
but not as soon a structure template is created.
Program 8.1
struct book
{
int bno;
char title[20];
float price;
};
void main()
{
struct book b;
Explanation
.
a) Structure elements are accessed using the dot ( ) operator.
b) In memory the book structure is organized as follows:
b
100
Program 8.2
/* array of structures */
struct book
{
int bno;
char title[20];
float price;
};
void main()
{
struct book b[5];
int n, i;
printf("How many books details do u want to enter:");
scanf("%d", &n);
void bradman(float* p)
{
float q = 1.5;
bradman( &q );
}
Explanation
It is called as a link function, which is used to link the Floating- point Emulator
software.
The Bug is: reading float member of a structure, using array of structures or pointer to
a structure.
Had we not used this dummy function, we would have got the runtime error:
struct student
{
int sno, age;
char sna[20], course[20];
float fee;
};
p = &s;
printf("%d, %d, %s, %s, %f", p->sno, p->age, p->sna, p->course, p->fee);
}
Explanation
48 bytes
Program 8.4
struct student
{
int sno, age;
char sna[20], course[20];
float fee;
};
void main()
{
struct student *p;
p = (struct student*)malloc( sizeof(struct student) );
printf("Enter student's details:");
scanf("%d%d%s%s%f", &p->sno, &p->age, p->sna, p->course, &p->fee);
printf("%d, %d, %s, %s, %f", p->sno, p->age, p->sna, p->course, p->fee);
}
void bradman(float* p)
{
float q = 8.2;
bradman(&q);
}
Explanation
p
222
Program 8.5
struct student
{
int sno, age;
char sna[20], course[20];
float fee;
};
void main()
{
struct student *p;
int n, i;
printf("How many students details do u want to enter:");
scanf("%d", &n);
void bradman(float* p)
{
float q = 8.2;
bradman(&q);
}
Program 8.6
struct employee
{
int eno, age;
char ena[30], desig[30];
float sal;
};
void main()
{
struct employee e1 = { 11, 27, "Sambhu Singh", "Commissioner of Police",
35000.00 }, e2;
e2 = e1;
printf("%d, %d, %s, %s, %f\n", e1.eno, e1.age, e1.ena, e1.desig, e1.sal);
printf("%d, %d, %s, %s, %f\n", e2.eno, e2.age, e2.ena, e2.desig, e2.sal);
}
Explanation
Note that structure elements (fields) cannot be initialized inside the structure template,
because a structure template is only a general form, memory is not allocated for
structue template.
Program 8.7
struct employee
{
int eno, age;
char ena[30], desig[30];
float sal;
};
t = *p;
*p = *q;
*q = t;
}
void main()
{
swap(&e1, &e2);
printf("%d, %d, %s, %s, %f\n", e1.eno, e1.age, e1.ena, e1.desig, e1.sal);
printf("%d, %d, %s, %s, %f\n", e2.eno, e2.age, e2.ena, e2.desig, e2.sal);
}
8.8 typedef
We know that alias names are easier to refer, than the original names.
Eg : Original name : Konedela Shiva Sankar Vara Prasad
Alias name : Chiranjeevi
Program 8.8
/* use of typedef */
struct employee
{
int eno, age;
char ena[30], desig[30];
float sal;
};
void main()
{
employee e1 = { 11, 27, "Kishore", "Marketing Manager", 11000.00 };
employee e2 = { 12, 27, "Vinodh", "Deputy Centre Manager", 13000};
swap(&e1, &e2);
printf("%d, %d, %s, %s, %f\n", e1.eno, e1.age, e1.ena, e1.desig, e1.sal);
printf("%d, %d, %s, %s, %f\n", e2.eno, e2.age, e2.ena, e2.desig, e2.sal);
}
Structure with a structure ( group of multiple types, within a group of multiple types) is
called as nested structure.
Program 8.9
/* nested structures */
struct address
{
int dno;
char street[20], area[20], city[20];
};
struct student
{
int sno;
char sna[20], course[20];
float fee;
struct address a;
};
void main()
{
struct student s;
printf("%d, %s, %s, %f, %d, %s, %s, %s", s.sno, s.sna, s.course, s.fee, s.a.dno,
s.a.street, s.a.area, s.a.city);
}
Program 8.10
#include<dos.h>
void main()
{
struct date d;
struct time t;
getdate(&d);
gettime(&t); to fill the blanks with zeros
Explanation
8.11 unions
unions are similar to structures, except the fact that memory allocated for a union
variable is memory required for the largest field.
Program 8.11
/* unions - example 1 */
union sample
{
int n;
char st[20];
float c;
double d;
};
void main()
{
union sample s;
printf("%d", sizeof(s) );
}
Output
20
Program 8.12
/* unions - example 2 */
#include<stdio.h>
union sample
{
double a;
float b[2];
char c[8];
};
void main()
{
union sample s;
int i;
s.a = 1345.672;
printf("%lf\n", s.a);
s.b[0] = 1.43;
s.b[1] = 82.6;
printf("%f, %f\n", s.b[0], s.b[1]);
Explanation
At a time only one field’s value can be stored. Note that the memory allocated for a
union can be accessed in several formats, i.e., as ints / chars / floats / double etc.
8.12 enum
There is one other kind of constant, the enumeration constant. An enumeration is a list
of constant integer values.
Ex 3 enum months { JAN = 1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV,DEC};
1 2 3 4 5 6 7 8 9 10 11 12
The first name is an enum, has value 0, the next 1, and so on, unless explicit values are
specified. If not all values are specified, unspecified values continue the progression
from the last specified value.
Remember that the constant names in different enumerations must be distinct, values
need not be distinct in the same enumeration.
Program 8.13
/* enum - example 1 */
void main()
{
printf("%d", THU);
}
Output
4
enum Vs macros (#define)
Rule : A player rolls two dice. Each dice has 6 faces. These faces contains : 1, 2, 3, 4, 5, 6
spots. After the dice have come to rest, the sum of the spots on the two upward faces is
calculated.
If the sum is 7 or 11 on the first throw, the player wins. If the sum is 2, 3 or 12 on the
first throw, the player loses. If the sum is 4,5, 6, 8, 9 or 10 on the first throw, then the
sum becomes the player’s point. To win, the player must continue rolling the dice until
the player makes his point.
Program 8.14
/* enum - example 2 */
#include<stdlib.h>
int rollDice()
{
int d1, d2, d3;
d1 = 1 + random( 6 );
d2 = 1 + random( 6 );
d3 = d1 + d2;
return d3;
}
void main()
{
int s, gs, mypoint;
randomize();
s = rollDice();
switch( s )
{
case 7 :
case 11:
gs = WON;
break;
case 2:
case 3:
case 12:
gs = LOST;
break;
default :
gs = CON;
mypoint = s;
printf("Player's point is %d\n", mypoint);
}
while( gs == CON )
{
s = rollDice();
if(s == mypoint)
gs = WON;
else if( s == 7)
gs = LOST;
}
if(gs == WON)
printf("Player won");
else
printf("Player lost");
}
Exercise
1.
Topic # 9
Atish Jain
Round-1
9.1 Console I/O and Disk I/O
Till now we have been doing console I/O. i.e., reading the data from the console input
device (keyboard) and sending the output to the console output device (screen).
Disk I/O
Reading the data from a disk file(usually Hard disk) and sending the output to a disk
file (usually Hard disk).
Disk I/O means storing the data on a secondary storage device using files.
Use
a) Suppose that today you have written a program, which reads a hundred names,
sorts them
into alphabetical order and prints them. You would undergo the following steps:
step1 : Write the program
step2 : Compile it
step3 : Execute it
step4 : Enter all the hundred names
step5 : Data is processed
step6 : See the output
Suppose that after few days you want to view the same output again. What would you
do? Execute that program once again and enter the hundred names all over again.
Instead won’t it be nice if we could store the result in a separate disk file and whenever
required just open that file and see the result. To accomplish this task we have to
perform disk output operations.
b) Suppose that you want to find the maximum of a set of numbers. What would you
do?
step1 : Write the program
step2 : Compile it
step3 : Execute it
step4 : Enter a set of numbers (say, hundred)
step5 : Data is processed
step6 : See the output
Suppose that after few days you want to perform a different operation (say, sum of
numbers) on the same data. What would you do?
Instead won’t it be nice if you could read the data (hundred numbers) from a disk file.
To accomplish this task we have to perform disk input operations.
File operations:
1. Text files
a. Text files stores character data
b. Text files are readable
c. Text files are processed sequentially ( character by character)
2. Binary files
a. Binary files stores data in binary format
b. Binary files are non readable
c. Random access
void main()
{
char st[10][30], temp[30];
int n, i, j;
FILE *fp;
fp = fopen("sort2.txt", "w");
for(i=0;i<n-1;i++)
{
for(j=0;j<n-1-i;j++)
{
if( strcmp(st[j], st[j+1] ) > 0 )
{
strcpy(temp, st[j]);
strcpy(st[j], st[j+1]);
strcpy(st[j+1], temp);
}
}
}
fclose(fp);
}
Explanation
a) After executing the program, goto command prompt and view the contents of
file1.txt.
b) FILE *fp;
Creates a FILE pointer ‘fp’.
FILE is a special structure (pre-defined). While performing disk I/O this FILE structure
should be used.
c) fopen()
Before reading/writing into a file, first that file should be opened. This task is done by
the fopen() libray function.
fopen() takes two arguments - file to open and file mode.
e) fclose()
Every file opened should be closed. This job is done by the fclose() function.
Even though we don’t close the file, it gets closed at the end of the program, However,
during the execution of the program, if it needs to be opened again, it has to
closed.(just like, a door can be opened only if it is in closed state)
Note: If buffer area is not created for I/O operations, then the program execution
becomes very slow (at the speed of disk rather than at the speed of processor)
void main()
{
int a[10], n, i, j, t;
FILE *fp;
fp = fopen("input1.txt", "r");
for(i=0;i<n;i++)
fscanf(fp, "%d", &a[i]);
for(i=0;i<n-1;i++)
{
for(j=0;j<n-1-i;j++)
{
if( a[j] > a[j+1])
{
t = a[j];
a[j] = a[j+1];
a[j+1] = t;
}
}
}
for(i=0;i<n;i++)
printf("%d\n", a[i]);
fclose(fp);
getch();
}
#include<stdio.h>
void main()
{
FILE *fp;
char ch;
fp = fopen("data1.txt", "w");
fclose(fp);
}
Explanation
b) EOF is a macro whose value is –1. This program keeps on reading until the uses
press the end of input key ( CTRL + Z ). So when this key is encountered, getchar()
function returns -1.
.
Program 9.4
#include<stdio.h>
void main()
{
FILE *fp;
char ch;
fp = fopen("file1.txt", "r");
while( 1 )
{
ch = fgetc(fp);
if(ch == EOF)
break;
printf("%c", ch);
}
fclose(fp);
}
Explanation
a) Every text mode file has a special character at its end called as end of the file
character (ASCII VALUE 26).
b) fputc() returns –1 when end of the file character is encountered.
Round-2
#include<stdio.h>
struct student
{
int rno, age;
char sna[20], course[20];
float fee;
};
void main()
{
FILE *fp;
char ch;
struct student s;
fp = fopen("stud1.txt", "w");
while( 1 )
{
printf("\nEnter student details : ");
scanf("%d%d%s%s%f", &s.rno, &s.age, s.sna, s.course, &s.fee);
fflush(stdin);
printf("Another record?[y/n]:");
ch = getche();
if(ch != 'y')
break;
}
fclose(fp);
}
Explanation
fprintf() is used to write record by record, where as fputc() is used to write character
by character.
#include<stdio.h>
struct student
{
int rno, age;
char sna[20], course[20];
float fee;
};
void main()
{
FILE *fp;
struct student s;
fp = fopen("stud1.txt", "r");
Output
Explanation
#include<stdio.h>
struct student
{
int rno, age;
char sna[20], course[20];
float fee;
};
void main()
{
FILE *fp;
char ch, st[20];
struct student s;
fp = fopen("stud1.txt", "r");
fclose(fp);
}
Round-3
Disk I/O
Library
Functions
Till now we discussed high-level text mode file handling. Lets now discuss high-level
binary mode file handling, later on we will disk low-level file handling in the next
chapter.
The binary mode library functions, handle the data in binary form. This means that the
data is stored in the disk in the same format (same number of bytes) as is stored in the
primary memory (RAM).
Advantages
a) There are no convertions while saving/ retriving the data and therefore file
handling is much faster.
b) Remains encrypted (unreadable by humans) – One cannot understand the contents
through the type command.
Note that in text mode file handling, an int occupies 2 bytes whereas in the disk it
depends upon the number of digits a particular int value has. Similar is the case with
float values.
There are three main areas where text and binary mode functions are different:
#include<stdio.h>
struct student
{
int rno, age;
char sna[20], course[20];
float fee;
};
void main()
{
FILE *fp;
char ch;
struct student s;
fp = fopen("stud2.bin", "wb");
while( 1 )
{
printf("\nEnter student details : ");
scanf("%d%d%s%s%f", &s.rno, &s.age, s.sna, s.course, &s.fee);
fflush(stdin);
printf("Another record?[y/n]:");
ch = getche();
if(ch != 'y')
break;
}
fclose(fp);
}
Explanation
Program 9.9
#include<stdio.h>
struct student
{
int rno, age;
char sna[20], course[20];
float fee;
};
void main()
{
FILE *fp;
struct student s;
fp = fopen("stud2.bin", "rb");
fclose(fp);
}
Round-4
File accessing
Till now we have been doing sequential file accessing. i.e., to access a record (or a
particular byte ) we have to go through all its previous records ( or bytes). However in
random file accessing to access a record (or a particular byte) we can directly reach
that point. Hence, random file accessing is much faster than sequential file accessing.
Lets see how this can be accomplished.
Program 9.10
#include<stdio.h>
void main()
{
student s;
FILE *fp;
int bytenumber;
fp = fopen("student1.obj", "rb");
fseek(fp, 0 , SEEK_END);
bytenumber = ftell(fp);
fclose(fp);
getch();
}
#include<stdio.h>
struct student
{
int rno, age;
char sna[20], course[20];
float fee;
};
void main()
{
FILE *fp;
struct student s;
int recordno, position;
fp = fopen("stud2.bin", "rb");
fclose(fp);
}
Explanation
a) fseek() happens to be one more library function. It moves the file pointer by a
quantity of specified number of bytes.
b) SEEK_SET is a macro. It indicates, to move the file pointer from the beginning of the
file.
There are two more macros:
SEEK_CUR : It indicates, to move the file pointer from the current location of the file.
SEEK_END : It indicates, to move the file pointer from the end of the file.
c) Suppose that, we want to view record number five. So we have to move to the
starting byte number of record number five. Using fseek() we move to the end of
fourth record Hence the code : position = ( recordno – 1 ) * sizeof( s ) . fseek()
automatically positions the cursor at the specified byte (+ 1) location . i.e., the starting
address of record number 5.
d) We know that fread() function extracts the data from the current file pointer
position ( i.e., record number five)
e) ftell() is another library function. It returns the byte position of the pointer.
Round-5
Actually we cannot delete anything form the memory (RAM/ DISK). It is only the
technique of memory management, i.e., reserving/ unreserving the memory.
/* deleting a record */
Program 9.12
#include<stdio.h>
struct student
{
int rno, age;
char sna[20], course[20];
float fee;
};
void main()
{
FILE *fp1, *fp2;
struct student s;
int n;
fclose(fp1);
fclose(fp2);
remove("school1.bin");
rename("temp.bin", "school1.bin");
}
Explanation
a) Before removing/ renaming a file, we have to disassociate the link between the file
pointer and the file being accessed. Hence we have closed the files.
/* modifying a record */
Program 9.13
#include<stdio.h>
struct student
{
int rno, age;
char sna[20], course[20];
float fee;
};
void main()
{
FILE *fp1, *fp2;
struct student s;
int n;
fclose(fp1);
fclose(fp2);
remove("school1.bin");
rename("temp.bin", "school1.bin");
}
Round-6
9.11 Putting it all together
void append()
{
FILE *fp;
student s;
char ch; append mode
fp = fopen("studdata.bin", "ab");
while( 1 )
{
printf("Enter student details:");
scanf("%d%d%s%s%f", &s.rno, &s.age, s.sna, s.course, &s.fee);
fflush(stdin);
printf("Another record?[y/n]:");
ch = getche();
if(ch != 'y')
break;
}
fclose( fp );
}
void display()
{
FILE *fp;
student s;
fp = fopen("studdata.bin", "rb");
printf("\n");
fclose(fp);
}
void filter()
{
FILE *fp;
student s;
char st[20];
fp = fopen("studdata.bin", "rb");
printf("\n");
fclose(fp);
}
void delete()
{
FILE *fp1, *fp2;
student s;
int n;
fp1 = fopen("studdata.bin", "rb");
fp2 = fopen("temp.bin", "wb");
fclose(fp1);
fclose(fp2);
remove("studdata.bin");
rename("temp.bin", "studdata.bin");
}
void modify()
{
FILE *fp1, *fp2;
student s;
int n;
fclose(fp1);
fclose(fp2);
remove("studdata.bin");
rename("temp.bin", "studdata.bin");
}
#include<stdio.h>
#include"struct.h"
#include"append.c"
#include"display.c"
#include"filter.c"
#include"delete.c"
#include"modify.c"
void main()
{
char ch;
while( 1 )
{
printf("*** Student database management system ***\n\n");
printf("1. Append\n");
printf("2. Display\n");
printf("3. Filter\n");
printf("4. Delete\n");
printf("5. Modify\n");
printf("6. Exit\n\n");
printf("Enter u'r choice:");
ch = getche();
switch( ch )
{
case '1' : append();
break;
case '2' : display();
break;
case '3' : filter();
break;
case '4' : delete();
break;
case '5' : modify();
break;
case '6' : exit();
default : printf("Invalid choice");
}
}
}
Explanation
Whenever we want to add any data at the end of existing data, we have to open the file
in append mode.
File modes
wt/wb
rt/rb
at/ab
a) If file is absent, new file is created.
b) If file is present, loads the file into memory and sets pointer beyond last
character in file
Operation : wrinting at the end
wt+/wb+
rt+/rb+
at+/ab+
Exercise
1.
Topic # 10
Atish Jain
As the name indicates, Command line arguments are nothing but the arguments passed
to the program (main()) from the command prompt.
We know that when we link a program (F9), .exe file gets created. This file (program)
can also be used as a command, which can be executed at the DOS command prompt.
While typing the command, we can also pass some values to our program. These values
are
received by the main().
Passing arguments to the main() from command prompt is known as command line
arguments.
The two arguments which are accepted by main() are argc and argv.
argc – argument count, which is int type, contains count of the arguments.
argv – argument value, which is array of character pointers, maintains list of
arguments.
/* sum command */
Program 10.1
save this program as mysum.c
argument count argument values
Explanation
a) Don’t run this program by pressing Ctrl + F9. This must be executed at the
command prompt.
eg : c:\ahcareer\sum 10 20 30
b) ‘argc’ contains the number of arguments passed from the command prompt
(including the program name). It is just for readability that the parameter name is
‘argc’, it can be any variable name.
c) ‘argv’ is an array of character pointers which contains the base addresses of each of
the arguments.
Lets create our own type command (which displays the contents of a file, on the
screen)
/* type command */
Program 10.2
save this program as mytype.c
#include<stdio.h>
void main(int argc, char* argv[] )
{
FILE *fp;
char ch;
printf("%c", ch);
}
fclose(fp);
}
Explanation
c:\ahcareer\mytype file1.txt
Lets create our own copy command (which copies the contents of a file into another
file)
/* copy command */
Program 10.3
save this program as mycopy.c
#include<stdio.h>
void main(int argc, char* argv[] )
{
FILE *fp1, *fp2;
char ch;
fp1 = fopen( argv[1], "r");
fp2 = fopen( argv[2], "w");
while( 1 )
{
ch = fgetc(fp1);
if(ch == EOF)
break;
fputc(ch, fp2);
}
fclose(fp1);
fclose(fp2);
}
Explanation
Lets create a special copy command (which copies the contents of a file into multiple
files)
Program 10.4
save this program as mulcopy.c
#include<stdio.h>
while( 1 )
{
ch = fgetc(fp1);
if(ch == EOF)
break;
fputc(ch, fp2);
}
rewind(fp1);
}
fclose(fp1);
fclose(fp2);
Explanation
After the completion of copying of file1.txt contents into f1.txt the file1.txt pointer
(fp1) would be at the end of the file. So we have to reposition the f1.txt file pointer
(fp1) at the beginning of the file so that it can be copied into another file. This job can
be accomplished using rewind() function which happens to be another library function.
Using High level disk I/O functions we could copy only text files but not the .exe / .obj /
.lib / .com files. The following program can copy even these type of files.
In Low-level disk I/O data is written/read as buffer full of bytes, rather than int / float
/ char / strings / structures as is done using high level disk I/O functions.
while( 1 )
{
bytes = read(in, buff, 512);
if(bytes > 0)
write(out, buff, bytes);
else
break;
}
close(in);
close(out);
}
Explanation
How to run this program?
a) open() : We know that fopen() returns a file structure pointer, but in Low – level
disk I/O, open() returns an integer value called file handle. This is a number assigned
to a particular file, which is used thereafter to refer to the file. If open() returns –1 it
means that the file couldn’t be opened successfully.
c) read() functions reads a maximum of specified number of bytes into the specified
char array from the specified file and returns a number which contains the number of
bytes actually read.
d) write() function writes specified number of bytes from the specified char array into
the specified file.
Exercise
11. OTHERS
1.
Topic # 11
Atish Jain
1. Characteristics of C
(That defines the language & also has lead to its popularity)
2. Features of C
• It influenced many languages like C++, C#, Java, Perl, Python, PHP etc
• Its use of modularity. Sections of code can be stored in libraries for re-use in
future programs
• First programming language developed by a programmer.
3. Compilation Vs Interpretation
Compilation: conversion of the entire source code into machine code.
Pros
• As the entire machine code which has to be executed is completely available, so
faster execution
Cons
• Any changes to the source code requires complete recompilation
Interpretation: conversion of one instruction into machine code and execute it. The
process
continues till the end of the program. So execution is a part of interpretation
Pros
• The primary advantage is that we can run the source code program to test its
operation, make a few changes & run it again directly. This can enormously
speed up the development/testing process.
• Although compiled programs execute faster than interpreted programs,
interpreters are popular in program development environment in which
programs are changed frequently as new features are added & logical/runtime
errors are corrected.
• Interpreters are much easier to build than a compiler.
Cons
• As source code has to be first converted into machine code and then executed, so
execution would be slower
• Interpreter s/w has to be loaded into RAM along with the program, so more
memory is required
• No copy of the machine code (executable code) exists on the disk.
Examples
Operating Systems, Compilers/ Interpreters (also called as Language processors),
Device Drivers, utility software, Graphics libraries, firmware
Device Driver: is a s/w corresponding to a h/w. When we buy any h/w like
printer/scanner and plug it to the Computer, it won’t work directly. First the
corresponding s/w (device driver) should be loaded. Note that for some h/w, device
driver s/w comes along with the Operating System (like Windows XP)
Examples: printer drivers, scanner drivers, keyboard drivers, mouse drivers, pen drive
driver, webcam drivers, LAN card drivers, sound drivers etc
Utility Software: also known as service program is a type of computer s/w specifically
designed to help manage and tune the computer h/w, OS.
Examples: disk defragmentation, system profiles, virus scanners, compression, network
managers etc
Firmware: software stored on integrated circuits eg. ROM
Appendix
II. STRING
III. FILES
C. BIBLIOGRAPHY
Title Author
______________________________________________________________________________
______________________________________________________________________________
______________________________________________________________________________
______________________________________________________________________________
______________________________________________________________________________
______________________________________________________________________________
______________________________________________________________________________
______________________________________________________________________________
______________________________________________________________________________
Name :______________________________________
Course Attended____________________________
________________________________________________
________________________________________________