MCA C Programming Course Overview
MCA C Programming Course Overview
Mukthagangotri, Mysore-570006
PROGRAMMING WITH C
Developed by the Department of Studies and Research in Computer Science, under the guidance of
Dean (Academic), KSOU, Mysuru.
Karnataka State Open University, June -2024.
All rights reserved. No part of this work may be reproduced in any form or any other means, without
permission in writing from the Karnataka State Open University.
Further information on the Karnataka State Open University Programmes may be obtained from the
University’s Office at Mukthagangotri, Mysore – 570 006.
Printed and published on behalf of Karnataka State Open University, Mysore-570 006 by the Registrar
(Administration)- 2024
TABLE OF CONTENTS
UNIT-12 Dynamic memory allocation, Malloc () method, Calloc () method, Free () method,
207-228
Realloc() method
BLOCKIV
LINKED LISTS
UNIT-13 Singly Linked list, Circular linked List, doubly linked list 229-258
UNIT-14 Stack, QUEUE, Implementation of Stack and QUEUE using array, Implementation 259-277
of stack and queue using linked list
UNIT-15 Recursion 278-283
UNIT-16 Structure, Union, function pointers, Handling errors and exceptions 284-310
Preface
Good style is emphasized. To create a good program, you must do more than just type
in code. It is an art in which writing and programming skills blend themselves
together to form a masterpiece. True art can be created. A well-written program not
only functions correctly, but is simple and easy to understand. Comments allow the
programmer to include descriptive text inside the program. When clearly written, a
commented program is highly prized. A program should be as simple as possible. A
programmer should avoid clever tricks. This book stresses simple, practical rules. For
example, there are 15 operator precedence rules in C. These can be simplified into
two rules:
This book is written for people with no previous programming experience or
programmers who already know C and want to improve their style and reliability.
You should have access to a computer and know how to use the basic functions such
as a text editor and the filesystem. Specific instructions are given for producing and
running programs using the UNIX operating system with a generic cc compiler or the
Free Software Foundation’s gcc compiler. For MS- DOS/Windows users,
instructions are included for Borland C++, Turbo C++, and Microsoft Visual C++.
(These compilers compile both C and C++ code.) The book also gives examples of
using the programming utility make for automated program production.
UNIT-1
INTRODUCTION TO C PROGRAMMING
Structure:
1.0 Objectives
1.1 Introduction
1.2 Overview of the C Language, History and Features
1.3 Summary
1.4 Keywords
1.5 Questions for self-study
1.6 References
1.0 OBJECTIVES
1.1 INTRODUCTION
A programming language is a set of symbols, grammars and rules (said to be syntax and
semantics of language). with the help of these, you will be able to translate algorithms to
programs that will be executed by the computer. The programmer communicates with a
machine using programming languages. Most of the programs have a highly structured set
of rules. The programming languages are classified in to machine language, assembly
language, high level language. Assembly language and high-level language programmes
are translated in to machine language using language translators: interpreter, assembler
and compiler. Algorithm and flowchart are used as aid to understand the program logic.
1
A computer or a system is operated by given a set of rules and instruction to perform some
tasks. These set of rules and instructions are able to control the working of computer or
any automated and/or manipulated machine. To control the computer system using these
sequential set of grammatical rules are known as programming language. A programming
language is a vocabulary and a set of grammatical rules for instructing a computer system
to perform any specific task. Hence, we can say that a programming language plays a very
important role to control and operate a computer system. The main classifications of
programming languages are:
o Machine Languages
o Assembly Languages
o High level Languages
Machine Language:
Machine language is a collection of binary digits (bits) that the computer reads and
interprets. Machine language is the only language that computer understands. It is the
lowest level and named as first generation of programming language. It is a language that
supports the machine side of the programming but difficult for human being to write and
remember the bit’s pattern. It consists of (binary) zeros and ones. Each instruction in a
program is represented by a numeric code, and numerical addresses are used throughout
the program to refer to memory locations in the computer’s memory.
E.g.; 101100111 is considered as a machine language instruction.
o It takes very less time to execute a program, because there is no conversion take
place.
Its machine dependent language i.e. individual program required for each machine.
2
To develop a program in machine language, it’s too hard to understand and
program.
Its time consuming to develop new programs.
Debugging process is very hard because of finding errors process is typical.
Machine language is not portable language.
Assembly language:
Assembly language is easier to use than machine language. It is a middle level and named
as second-generation programming language. An assembler is useful for detecting
programming errors. Programmers do not have the absolute address of data items.
Assembly language encourage modular programming. It uses mnemonic codes instead of
bit pattern for instructions. The programs written are machine dependent. Here assemblers
are used to translate assembly language code to machine language.
Example for assembly language program:
3
level language programs are machine independent. A line in a high-level language can
execute powerful operations and corresponds to tens, or hundreds, of instructions at the
machine level. Examples of high-level languages are BASIC, FORTRAN, C, COBOL,
PASCAL, C ++, JAVA.
Example:
#include<stdio.h> Int a; Scanf(“%d”, &a);
STRUCTURED PROGRAMMING
It can be defined as a programming approach in which the program is made as a single structure. It is an
approach to writing programs that are easier to test, debug, modify and maintain by enforcing a modular
approach which breaks a large complex problem into sub- problems. It is also called as modular
programming. The languages that support Structured programming approach are:
C
C++
Java
C#
..etc
4
In the Assembly languages like Microprocessor 8085, etc., the statements do not get executed in a
structured manner. It allows jump statements like GOTO. So, the program flow might be random. The
structured program consists of well-structured and separated modules. But the entry and exit in a
Structured program is a single-time event. It means that the program uses single-entry and single-exit
elements. Therefore, a structured program is well maintained, neat and clean program. This is the reason
why the Structured Programming Approach is well accepted in the programming [Link] structured
program mainly consists of three types of elements:
Sequence Statements
Selection Statements
Iteration Statements
Sequence statements: Executes list of statements in order one after the other in sequence. It includes the
simple assignment statement, read and write statements.
Example:
Int a,b;
Scanf(“%d”,&a);
Printf(“a=%d”,a);
b=a;
Selection statements:
In this structure, given one or more blocks of statements, based on decision, branches to a
5
particular block of statements. This structure also follows single entry and single exit concept.
6
6. Easier to Debug
7. Machine-Independent, mostly.
COMPILATION PROCESS
Compilation: The compiler program translates the instructions of a high-level language to a machine
level language. A separate compiler is required for every high-level language. High level language is
simply a programmer’s convenience and cannot be executed in their source. The actual high - level
program is called a source program. It is compiled (translated) to machine level language program called
object program for that machine by the compiler. Compiler compiles the full program and reports the
errors at the end of Compilation Process. Here we come across the terms source code, object code and
executable code.
Source code:
The input given to a compiler is called source code. Which is nothing but the user program written in high
level language.
Object code:
The output of the compiler is the machine level language code called object code readable by the machine.
Executable code : (also called the Binary) is the output of a linker after it processes the
object code. A machine code file can be immediately executable (i.e., runnable as a program),
7
or it might require linking with other object code files (e.g., libraries) to produce a complete executable
[Link] compilation and execution process of C program can be divided in to multiple steps:
Preprocessing: Using a Preprocessor program to convert C source code in expanded source code.
"#include" and "#define" statements will be processed and replaced actually source codesign this step.
Compilation: Using a Compiler program to convert C expanded source to assembly source code.
Assembly Using a Assembler program to convert assembly source code to object code. Linking Using
a Linker program to convert object code to executable code. Multiple units of object codes are linked
to together in this step.
Loading Using a Loader program to load the executable code into CPU for execution. Compilation
Linking:
After all of the files are compiled, they must be "merged together" to produce a single executable file that
the user use to run the program. In C, most compiled programs produce results only with the help of
some standard programs, known as library files that reside in the
8
computer. This process is called linking. The result obtained after linking is called the executable file. The
linker′s primary function is to bind symbolic names to memory addresses. To do this, it first scans the
files and concatenates the related file sections to form one large file. Then, it makes a second pass on the
resulting file to bind symbol names to real memory [Link] are two types of linking: Static
linking and dynamic linking.
Static linking: It occurs at compilation time; Hence it occurs prior to loading a program. With static
linking the external symbols that are used by the program (e.g., function names) are resolved at compile
time.
Dynamic linking: It occurs at run time, so it occurs after or at the time of the loading of a program. With
dynamic linking the symbols are resolved either at loading time, or at run time when the symbol is
accessed.
Loader: It is a part of operating system and is responsible for loading executable files into memory and
execute them. It calculates the size of a program (instructions and data) and creates memory space for it.
It initializes various registers to initiate execution.
Language Translators:
Assembler, interpreter and compilers are called language translators. They translate assembly and high-
level language programs to machine language. Assembler translates assembly language to machine
language. Interpreter and compiler translate high level language to machine language. The difference
between interpreter and compiler is that Interpreter translates high level language program to machine
language line by line. If an error occurs, an interpreter stops execution and reports it. whereas a compiler
reads the whole program even if it encounters several errors. The procedure for turning a program written
in C into machine Language. The process is presented in a straightforward, linear fashion but you should
recognize that these steps are repeated many times during development to correct errors and make
improvements to the code. The following are the four steps in this process.
9
3) Linking the program with the required modules
4) Executing the program
10
reads the translation unit and writes the resulting object module to a file that can then be combined with
other precompiled units to form the final program. An object module is the code in the machine language.
The Linker assembles all functions, the program ‘s functions and system ‘s functions into one executable
program. To execute a program, we use an operating system command, such as run, to load the program
into primary memory and execute it.
Algorithm is a finite sequence of instructions, each of which has a clear meaning and can be performed
with a finite amount of effort in a finite length of time. No matter what the input values may be, an
algorithm terminates after executing a finite number of instructions. We represent an algorithm using a
pseudo language that is a combination of the constructs of a programming language together with
informal English statements. The ordered set of instructions required to solve a problem is known as an
algorithm. The characteristics of a good algorithm are:
o Precision – the steps are precisely stated (defined).
o Uniqueness – results of each step are uniquely defined and only depend on the input and
the result of the preceding steps.
o Finiteness – the algorithm stops after a finite number of instructions are executed.
Example Q. Write an algorithm to find out whether the given number is odd or even. Ans.
step 1 : start
11
step 3 : rem=number mod 2
step 4 : if rem=0 then print "number even" else print "number odd" endif step
5:stop
FLOWCHART
Flowchart is a pictorial representation of logic of the program. Flowchart is very helpful in writing
program and explaining program to others. It uses several standard symbols in the diagram.
Different symbols are used for different statements in flowchart, For example: Input/output and decision
making has different symbols. The table below describes all the symbols that are used in making
flowchart.
12
Example 1: Draw a flowchart to add two numbers entered by the user.
Example2: draw flowchart to find largest of three numbers entered by the user.
13
1.2 OVERVIEW OF THE C LANGUAGE, HISTORY AND FEATURES
C has played a pivotal role in shaping today’s technological landscape. It is one of the
most popular and oldest programming languages, known for its versatility, efficiency, and
speed. It was designed as the system programming language for Unix OS but gained
popularity due to its portability and flexibility. It is a portable language, meaning written
code can easily be compiled and run on other operating systems and platforms. It is the
language of technology and innovation, powering everything from the operating system
to smartphones. It contains the applications of video games, mobile applications, and
system software. The key strength of this language is to access and manipulate the
memory address. The syntax of c language is simple, so it allows efficient memory
management. Whether you are an aspiring developer or a computer science student,
understanding C is necessary for unlocking programming secrets.
14
History: C has often been termed as a "Pseudo high level language" or a "Middle level
language" by many programmers. This is not because of its lack of programming power
but because of its capability to access the system's low-level functions. In fact, C was
invented specifically to implement UNIX. C instructions are compiled to assembly code,
therefore, depending on the complexity of the code and on the compiler optimization
capabilities, C code may run as fast as assembly. Ken Thompson created the B language
in 1969 from Martin Richard's BCPL (Basic Combined Programming Language). He
used assembly language and B to produce the initial versions of the UNIX operating
system. BCPL and B were type less languages in which variables were simply words in
memory. Dennis Ritchie of Bell Laboratories later converted B into C by retaining most
of B's syntax in 1972 and wrote the first compiler. This was implemented on DEC's PDP
11 and it was first used as the system's language for rewriting the UNIX operating
system. Later on, UNIX, its tools and C grew simultaneously. In 1978, Kernighan and
Ritchie wrote a book entitled 'The C Programming Language' that became the language
definition for almost a decade. Beginning in 1983, the ANSI X3J11 committee was asked
to standardize the C language. The result was ANSI C, a standard which was adopted in
1988. It is not forced upon any programmer, but since it is so widely accepted, it would be
economically unwise for any systems programmer or compiler writer not to conform to
the standard.
15
1.3 SUMMARY
In this unit, you have studied the C is a powerful, general-purpose, and procedural
programming language developed by Dennis Ritchie at Bell Labs in the early 1970s. It
was initially designed for developing the UNIX operating system and has since become a
foundational language in computer science and History and Features
1.4 KEYWORDS
Overview
C Language
History
Features
1.6 REFERENCES
16
UNIT-2
C LANGUAGE FUNDAMENTALS
Structure:
2.0 Objectives
2.1 Introduction
2.2 The C language and its advantages
2.3 Structure of A C program
2.4 Writing C program
2.5 C tokens and identifiers
2.6 Data types and variables
2.7 Variable declaration in C
2.8 Constants in C
2.9 Constant declaration in C
2.10 Summary
2.11 Keywords
2.12 Questions for self-study
2.13 References
2.0 OBJECTIVES
After studying this unit, you will be able to
2.1 INTRODUCTION
C was developed by Dennis Ritchie at Bell Laboratories in 1972. Most of its principles and ideas were
taken from the earlier language B, BCPL and CPL. CPL was developed jointly between the Mathematical
Laboratory at the University of Cambridge and the University of London Computer Unit in 1960s. CPL
(Combined Programming Language) was developed with the purpose of creating a language that was
capable of both machine independent programming and would allow the programmer to control the
behavior of individual bits of information.
17
But the CPL was too large for use in many applications. In 1967, BCPL (Basic Combined Programming
Language) was created as a scaled down version of CPL while still retaining its basic features. This process
was continued by Ken Thompson. He made B Language during working at Bell Labs. B Language was a scaled
down version of BCPL. B Language was written for the systems programming. In 1972, a co-worker of Ken
Thompson, Dennis Ritchie developed C Language by taking some of the generality found in BCPL to the B
language. The original PDP-11 version of the UNIX system was developed in assembly language. In 1973, C
language had become powerful enough that most of the UNIX kernel was rewritten in C. This was one of the
first operating system kernels implemented in a language other than assembly. During the rest of the 1970's, C
spread throughout many colleges and universities because of its close ties to UNIX and the availability of C
compilers. Soon, many different organizations began using their own versions of C Language. This was
causing great compatibility problems. In 1983, the American National Standards Institute (ANSI) formed a
committee to establish a standard definition of C Language. That is known as ANSI Standard C. Today C is
the most widely used System Programming Language.
18
Modularity: Ability to breakdown a large module into manageable sub modules called as modularity,
which is an important feature of structured programming languages.
Advantages:
Projects can be completed in time.
Debugging will be easier and faster.
Portability: The ability to port i.e., to install the software in different platform is called portability.
Highest degree of portability: ‘C’ language offers highest degree of portability i.e., percentage of changes
to be made to the sources code is at minimum when the software is to be loaded in another platform.
Percentage of changes to the source code is minimum. The software that is 100% portable is also called as
platform independent software or architecture neutral software. E.g.: Java.
Extendibility: Ability to extend the existing software by adding new features is called as extendibility.
SPEED:‘C’ is also called as middle level language because programs written in ‘c’ language run at the
speeds matching to that of the same programs written in assembly language so ‘c’ language has both the
merits of high level and middle level language and because if this featureit is mainly used in developing
system software.
Flexibility: Key words or reverse words
ANSI C has 32 reverse words
‘C’ language has right number of reverse words which allows the programmers to have complete control on the
language.
‘C’ is also called as programmer’s language since it allows programmers to induce creativeness into the
programmers.
19
function. The main ( ) function can be preceded by documentation, preprocessorstatements and global
declarations.
Documentations
The documentation section consist of a set of comment lines giving the name of the program, another name
and other details, which the programmer would like to use later.
Preprocessor Statements
The preprocessor statements begin with # symbol and are also called the preprocessor directive. These
statements instruct the compiler to include C preprocessors such as header files and symbolic constants
before compiling the C program. Some of the preprocessor statements are listed below.
20
Global Declarations
The variables are declared before the main ( ) function as well as user defined functions are called global
variables. These global variables can be accessed by all the user defined functions including main ( )
function.
Braces
Every C program should have a pair of curly braces ({, }). The left braces indicates thebeginning of the
main ( ) function and the right braces indicates the end of the main ( ) function. These braces can also be
used to indicate the user-defined functions beginning and ending. Thesetwo braces can also be used in
compound statements.
Local Declarations
The variable declaration is a part of C program and all the variables are used in main ( ) function should
be declared in the local declaration section is called local variables. Not only variables, we can also
declare arrays, functions, pointers etc. These variables can also be initialized with basic data types.
21
For Example
Main ( )
{
int sum = 0; int
x;
float y;
}
Here, the variable sum is declared as integer variable and it is initialized to zero. Other variables declared as int
and float and these variables inside any function are called local variables.
Program statements
These statements are building blocks of a program. They represent instructions to the computer to
perform a specific task (operations). An instruction may contain an input-output statements, arithmetic
statements, control statements, simple assignment statements and any other statements and it also includes
comments that are enclosed within /* and */. The comment statements are not compiled and executed
and each executable statement should be terminated with semicolon.
Press ALT+F9 to compile your program. If you have any error in your program, you will get the message,
remove your errors and then execute your program you will got the output.
Hello World
Welcome to C Programming
22
Some other sample C programs
/*Display Current date and time*/ /* addition of 2 numbers */
#include <stdio.h> #include<stdio.h>
#include <time.h> #include<conio.h>
void main() void main()
{ {
time_t t; int a, b,c;
time(&t); c=0;
clrscr(); a=3;
printf("Today's date and time : s",ctime(&t)); b=4;
getch(); c = a + b:
} printf(“result of addition = %d”,c);
}
2.3 C TOKENS AND IDENTIFIERS
23
The individual tokens are:
In C program, the semicolon is a statement terminator. That is, each individual statement must be ended with a
semicolon. It indicates the end of one logical [Link] example, following are two different statements:
Comments
Comments are like helping text in your C program and they are ignored by the compiler. They start with
/* and terminates with the characters */ as shown below:
You cannot have comments within comments and they do not occur within a string or character literals.
Identifiers
o Identifiers are the names given to variables, classes, methods and interfaces.
o It must be a whole word and starts with either an alphabet or an underscore.
o They are case sensitive.
o No commas or blanks are allowed in it
o No special symbol other than an underscore can be used in it.
Ex.: marks gracesem1_rollno alpha
Keywords
o Keywords are words that have special meaning to the C compiler.
o An identifier cannot have the same spelling and case as a C keyword.
o C makes use of only 32 keywords or reserved words which combine withthe formal
syntax to the form the C programming language.
o All keywords in C are written in lower case.
o A keyword may not be used as a variable name.
Whitespace means characters that exist in a file but appear blank in a printed listing of a file (or
traditionally did appear blank, several decades ago). The C language requires whitespace in order to
24
separate two consecutive identifiers, or to separate an identifier from a numeric constant. Other than that,
and a few special situations described later, whitespace is optional; you can put it in when you wish, to
make the code easier to [Link] and tab in C code are treated as whitespace characters. So are line
breaks. You can represent a line break with the newline character (also called linefeed or LF), CR
(carriage return), or the CRLF sequence (two characters: carriage return followed by a newline character).
The formfeed character, Control-L, was traditionally used to divide a file into pages. It is still used this
way in source code, and the tools that generate nice printouts of source code still start a new page after
each “formfeed” character. Dividing code into pages separated by formfeed characters is a good way to
break it up into comprehensible pieces and show other programmers where they start and end. The vertical
tab character, Control-K, was traditionally used to make printing advance down to the next section of a
page. We know of no particular reason to use it in source code, but it is still accepted as whitespace in
[Link] are also syntactically equivalent to whitespace. Adding a whitespace character in a scanf()
function causes it to read elements and ignore all the whitespaces as much as it can and search for a
non-whitespace character to proceed.
scanf("%d ");
scanf(" %d");
scanf("%d\n"); This is different
from scanf("%d"); function.
Example 1: The scanf function after reading the number starts reading further until it finds a non-
whitespace character on the input and prints the first number that was typed.
Adding whitespace or "\n" after format specifier in scanf function
scanf("%d ");
or
scanf("%d\n", );
25
2.4 DATA TYPES AND VARIABLES
The area of the program where that variable is valid, the amount of time that a variable is retained, as well
as where it can be accessed from, depends on its specified location and type. The life span of the
variable, i.e., the length of time that the variable remains in memory. The programmer has to be very
much aware of the type of the variable he/she going to use. Each and every sort of scenario requires
different type of scope. For example, suppose the variable which should remain constant and also required
by external functions then it is not good practice to declare same variable again and again instead of that it
may be called as a global variable.
On the other hand, for the sake security reason some variable has be visible in only one function can be
treated and declared as static variable. This section of the unit will be discussing thoroughly in forth
coming units when we introduce storage class and different types of variables. The basic data structure
used in C programs is a number. C provides for two types of numbers - integers and floating point.
Computer operations that involve text (characters, words or strings) still manipulate numbers. Each data
item used by a program must have a data type. The basic data types provided by C are shown in Table 1.
Each data type represents a different kind of number. You must choose an appropriate type for the kind of
number you need in the variable declaration section of the program.
26
Primary Data types:
char: The most basic data type in C. It stores a single character and requires a single byte of
memory in almost all compilers.
int: As the name suggests, an int variable is used to store an integer.
float: It is used to store decimal numbers (numbers with floating point value) with single precision.
double: It is used to store decimal numbers (numbers with floating point value) with double
precision.
Integer Data Type
Integers are numbers without decimal point
Integers are whole numbers with a range of values, range of values are machine
dependent.
Generally, an integer occupies 2 bytes memory space and its value range limited to
- 32768 to +32767 (that is, -215 to +215-1).
The following table provides the details of standard integer types with their storage sizesand value
ranges –
27
unsigned long 8 bytes 0 to 18446744073709551615
Format specifier for Int is %d.
For long int - %ld.
for short int-%hd.
Float and double data types: Real numbers are stored with the data type float and double.
The format specifier and the number of bytes occupied by the data types of real number are as shown in
table:
float 4 %f
double 8 %lf
long double
16 %Lf
Character data type: Keyword char is used for declaring character type variables. For example,
The size of the character variable is 1 byte. Format specifier for char type data is %c.
28
2.7 VARIABLE DECLARATION IN C
A variable is nothing but a name given to a storage area that our programs can manipulate. Each
variable in C has a specific type, which determines the size and layout of the variable's memory; the
range of values that can be stored within that memory; and the set of operations that can be applied to
the variable.
Type Description
char Typically, a single octet (one byte). This is an integer type.
int The most natural size of integer for the machine.
float A single-precision floating point value.
double A double-precision floating point value.
void Represents the absence of type.
Variable Declaration in C
A variable declaration provides assurance to the compiler that there exists a variable with the
given type and name so that the compiler can proceed for further compilation without requiring
the complete detail about the variable. A variable definition has its meaning at the time of
compilation only; the compiler needs actual variable definition at the time of linking the
program. A variable declaration is useful when multiple files are used. The syntax for declaration
of variable is as follows:
int i, j, k;
char c, ch;
29
float f, salary;
double d;
The line int i, j, k; declares and defines the variables i, j, and k; which instruct the compiler to create
variables named i, j and k of type [Link] will use extern keyword to declare a variable at any place. Though
you can declare a variable multiple times in your C program but it can be defined only once in a file, a
function ora block of code.
Example
Try following example, where variables have been declared at the top, but they have been defined and
initialized inside the main function:
#include <stdio.h>
// Variable declaration:
extern int a, b;
extern int c;
extern float f;
int main ()
{
/* variable definition: */ int a, b;
int c; float
f;
/* actual initialization */
a = 10;
b = 20;
c = a + b;
printf("value of c : %d \n", c); f =
70.0/3.0;
return 0;
30
When the above code is compiled and executed, it produces the following result:
value of c : 30
value of f : 23.333334
Same concept applies on function declaration where you provide a function name at the time of its
declaration and its actual definition can be given anywhere else. For example:
// function declaration
int func();
int main()
{
// function call int i
= func();
}
// function definition int
func()
{
return 0;
}
Variables can be initialized (assigned an initial value) in their declaration. The initializer consists of an
equal sign followed by a constant expression as follows –
type variable_name = value; Some
examples are –
extern int d = 3, f = 5; // declaration of d and f.
int d = 3, f = 5; // definition and initializing d and f. byte z =
22; // definition and initializes z.
char x = 'x'; // the variable x has the value 'x'.
31
For definition without an initializer: variables with static storage duration are implicitly initialized with
NULL (all bytes have the value 0); the initial value of all other variables is undefined.
2.8 CONSTANTS IN C
A constant value is the one which does not change during the execution of a program. C supports several types
of constants.
1. Integer Constants
2. Real Constants
3. Single Character Constants
4. String Constants
Integer Constants
An integer constant is a sequence of digits. There are 3 types of integers namely decimal integer, octal
integers and hexadecimal integer.
Decimal Integers consists of a set of digits 0 to 9 preceded by an optional + or - sign. Spaces, commas and
non digit characters are not permitted between digits.
Example for valid decimal integer constants are
123, -3, 0, 562321, + 78
Some examples for invalid integer constants are
15 750, 20,000, Rs. 1000
Octal Integers constant consists of any combination of digits from 0 through 7 with a O at the beginning.
Some examples of octal integers are
O26, O, O347, O676
Hexadecimal integer constant is preceded by OX or Ox, they may contain alphabets from A to F or a to f.
The alphabets A to F refers to 10 to 15 in decimal digits.
Example of valid hexadecimal integers are
OX2, OX8C, OXbcd, Ox
1. Real Constants
Real Constants consists of a fractional part in their representation. Integer constants are inadequate to
represent quantities that vary continuously. These quantities are represented by numbers containing
fractional parts like 26.083.
32
Example of real constants are
0.0026, -0.97, 435.29, +487.0
Real Numbers can also be represented by exponential notation. The general form for exponential notation
is mantissa exponent. The mantissa is either a real number expressed in decimal notation or an integer.
The exponent is an integer number with an optional plus or minus sign.
String Constants
String constant is a set of characters enclosed in double quotation marks. The characters in a string
constant sequence may be an alphabet, number, special character and blank space.
Example of string constants are
"VISHAL", "1234", "God Bless", "!. ......... ?"
The names given to constants must conform to the rules for the formation of identifiers as defined above.
The following constant declaration
const int days_in_year = 365;
defines an integer constant day_in_year which has the value 365. Later in the program the identifier
days_in_year can be used instead of the integer 365, making the program far more [Link] general
form of a constant declaration is:
33
Constant definitions are, by convention, usually placed before variable declarations. There is no limit on
how many constant declarations can be used in a program. Several constant identifiers of the same type
can be declared in the same constant declaration by separating each declaration by a comma. Thus
const int days_in_year = 365,
days_in_leap_year = 366;
2.10 SUMMARY
At the end of this unit, we have discussed about the basic concepts of C programming viz., c tokens:
Identifiers, Keywords, Variables and constants. Data types are mainly classified in to three groups: primary,
derived and user-defined datatypes. In the group primary data type, we have int, float, double and char. All
these data types are combined with signed/unsigned and short/long modifiers.
2.11 KEYWORDS
Identifier
Variable
Keyword
int, float
1. Explain the terms variable, keyword, constant and constant which are supported in C
programming.
2. Briefly describe the variable declaration in C program.
3. Discuss about the data type supported in C language.
4. Distinguish between local and global declaration.
34
2.13 REFERENCES
35
UNIT-3
Structure:
3.0 Objectives
3.1 Introduction
3.0 OBJECTIVES
After studying this unit, you will be able to
Explain the rich set of operators supported by C
Explain the operator’s precedence rule
Explain Expression in C
36
3.1 INTRODUCTION
In this unit, you are going to study the rich set of operators available in C, formation of expressions using
arithmetic operators, logical operators. In an expression, if more than one type of operator is appearing
then their order of evaluation will be learned in this unit. Assignment statement is the simple statement
which assigns the value of the expression/ value present on right hand side of the = sign to the variable
present on left hand side of equal sign. The necessary condition is that the date type of the value should be
same as that of the variable declared in declaration section. If the data type does not match, then type
casting is done.
In C, we have rich set of operators. An operator is a symbol that tells the compiler to perform specific
mathematical or logical functions and it is a symbol which operates on a variable or value. There are types
of operators like arithmetic, logical, conditional, relational, bitwise, assignment operators etc. Some
special types of operators are also present in C like size of(), Pointer operator, Reference operator etc.
In C programming, an assignment statement sets and/or re-sets the value stored in the storage location(s)
denoted by a variable name; in other words, it copies the value into the variable. In most imperative
programming languages, the assignment statement (or expression) is a fundamental construct.
Assignments typically allow a variable to hold different values at different times during its life-span and
scope. However, some languages (primarily strictly functional) do not allow that kind of "destructive"
reassignment, as it might imply changes of non-local state. The purpose is to enforce referential
transparency, i.e. functions that do not depend on the state of some variable(s), but produce the same
results for a given set of parametric inputs at any point in time. Assignment statement is a simple
statement having the following form: variable = expression
The expression to the right of the assignment operator is evaluated and the result is stored to the
variable on the left. Here are some rules:
37
The expression is evaluated first with the rules discussed
If the type of the expression is identical to that of the variable, the result is saved in the
variable.
Otherwise, the result is converted to the type of the variable and saved there.
o If the type of the variable is INTEGER while the type of the result is REAL, the
fractional part, including the decimal point, is removed making it an integer result.
o If the type of the variable is REAL while the type of the result is INTEGER, then
a decimal point is appended to the integer making it a real number.
Once the variable receives a new value, the original one disappears and is no more
available.
Examples:
The program segment below declares three INTEGER variables. The first assignment
statement saves an integer value to variable Unit. The second saves a real number 100.99
into variable Amount. However, since Amount is an INTEGER variable, the real value
100.99 is converted to an integer, 100, and saved into Amount. Thus, after the second assignment
completes variable Amount holds 100. The third assignment computes the single mode
expression, yielding a result 500 = 5*100. Thus, variable Total receives 500. int Total, Amount,
Unit;
Unit = 5;
Amount = 100.99;
Total = Unit * Amount;
INT A = 3, B = 5, C;
C = A;
A = B;
B = C;
The following swaps the values in A and B, with the help of C. That is, after completing the
following three assignment statements, A and B have 5 and 3, respectively.
38
Initially, A and B are initialized to 3 and 5, respectively, while C is uninitialized. The first
assignment statement puts A's value into C, making A=3, B=5 and C=3.
The second assignment statements put B's value into A. This destroys A's original value
2. After this, A = 5, B = 5 and C = 3.
The third assignment statement puts C's value into B. This makes A=5, B=3 and C=3. Therefore,
the values in A and B are exchanged.
1. Arithmetic operators
2. Assignment operators
3. Relational operators
4. Logical operators
5. Bit wise operators
6. Conditional operators (ternary operators)
7. Increment/decrement operators
8. Special operators
39
7 Increment/decrement These operators are used to either increase
operators or decrease the value of the variable by
one.
8 Special operators &, *, sizeof( ) and ternary operators.
40
NOT (!)
We use this operator for reversing the logical state of the available operand. It means that the logical NOT
operator will make an available condition to be false if it is already true.
In simple words,
If p is true, then !p will be false.
If p is false, then !p will be true.
Increment
We use this operator to increment the overall value of any given variable by a value of 1. We can perform
increment using two major ways:
Prefix increment
Postfix Increment
Prefix Increment
The operator in this method precedes the given operand (Example, ++p). Thus, the value of the operand gets
altered before we finally use it.
For instance,
int p = 1;
int q = ++p; // q = 2
Postfix Increment
The operator in this method follows the given operand (Example, p++). Thus, the value of the available
operand gets altered after we use it.
For instance,
int p = 1;
int q = p++; // q = 1 int
r = p; // r = 2
Decrement
We use this operator to decrement the overall value of any given variable by a value of 1. We can
perform decrement using two major ways:
Prefix Decrement
The operator in this method precedes the given operand (Example, –p). Thus, the value of the operand gets
altered before we finally use it.
For instance,
41
int p = 1;
int q = –p; // q = 0
Postfix Decrement
The operator in this method follows the given operand (Example, p–). Thus, the value of the available
operand gets altered after we use it.
For instance,
int p = 1;
int q = p–; // q = 1
int r = p; // r = 0
Address of Operator (&)
This type of operator provides the user with the address of any variable. The address of operator is used to
return the address (memory address) of any variable. The addresses that are returned using this operator
are called pointers. It is because they point towards the variable present in the memory.
For instance,
& gives an address on variable n int
a;
int *ptr;
ptr = &a; // address of a is copied to the location ptr.
42
*, / and % will be performed before + or - in any expression. Parenthesis can be used to force a different
order of evaluation to this. Where division is performed between two integers, the result will be an
integer, with remainder discarded. Modulo reduction is only meaningful between integers. If a program is
ever required to divide a number by zero, this will cause an error, usually causing the program to crash.
/ Operator gives the real value after complete division.
% operator gives the remainder after division (integer value).
The order of precedence of operators can be altered by using parenthesis and in case of nested
parenthesis, innermost parenthesis is evaluated first.
Example:-
Assume that integer variable A holds value 10 and variable B holds 20, then A+B
gives value 30
A-B gives value -10
B/A gives value 2 B%A
gives value 0
EXAMPLE PROGRAM FOR C ARITHMETIC OPERATORS
In this example program, two values ―40‖ and ―20‖ are used to perform arithmetic operations such as
addition, subtraction, multiplication, division, modulus and output is displayed for each operation.
#include <stdio.h>
int main()
{
int a=40,b=20, add,sub,mul,div,mod; add =
a+b;
sub = a-b;
mul = a*b;
div = a/b;
mod = a%b;
printf("Addition of a, b is : %d\n", add);
43
printf("Subtraction of a, b is : %d\n", sub);
printf("Multiplication of a, b is : %d\n", mul);
printf("Division of a, b is : %d\n", div); printf("Modulus of
a, b is : %d\n", mod);
}
OUTPUT:
Addition of a, b is : 60
Subtraction of a, b is : 20
Multiplication of a, b is : 800
Division of a, b is : 2 Modulus
of a, b is : 0
C provides you a list of relational operators to allow you to compare data. The relational operators enable
you to check whether two variables or expressions are equal, not equal, which one is greater or less than
other...etc. The relational operators are used to form boolean expressions which return logical value either
0 or [Link] following table illustrates the relational operators in C:
== Equal to
!= Not equal to
44
Suppose that a and b are integer variables whose values are 100 and 4, respectively. Several logical expressions
involving these variables are shown below, together with their resulting values.
a<b False 0
a>b True 1
a<=b False 0
a>=b True 1
a==b False 0
a!=b True 1
7.3.4 LOGICAL OPERATORS
A Logical operator is used to combine two or more logical expressions and to negate a logical
expression. There are three logical operators in C language. They are AND, OR and NOT operators.
For example
(x < 20 )&&(x >= 10) is a logical expression with logical operator &&. &&
operator gives the result TRUE if all the expressions give TRUE value.
| | operator gives the result TRUE if any one of the expressions is TRUE.
! operator gives the negation of the expression [Link], if the expression gives true value,
!(expression) gives false value.
Suppose that a and b are integer variables whose values are 100 and 4, respectively. Then,
45
3.3.5 BITWISE OPERATORS
Bitwise operators operate on individual bits of integer (int and long) values. This is useful for writing
low-level hardware or OS code where the ordinary abstractions of numbers, characters, pointers, and so
on, are insufficient. Bit manipulation code tends to be less "portable". Code is "portable" if without any
programmer intervention it compiles and runs correctly on different types of computers. The bit wise
operations are commonly used with unsigned types. These operators perform bit wise logical operations
on values. Both operands must be of the same type and width: the resultant value will also be this type and
width.
| Bitwise inclusive OR
^ Bitwise exclusive OR
~ one's complement
Example:
Bitwise Negation
a=00000011
~a =11111100
46
Bitwise AND
a = 00000011
b = 00010110
a&b=00000010
Bitwise OR
a = 00000011
b = 00010110
a|b=00010111
Bitwise Exclusive OR
a = 00000011
b = 00010110
a^b=00010101
Right Shift
a = 0000 0011 = 3
(a<<=1) = 00000110 = 6
(a<<=2) = 00011000 = 24
(a<<=3) = 11000000 = 192
Left Shift a=11000000
=192
(a>>=1) = 01100000 = 96
(a>>=2) = 00011000 = 24
(a>>=3) = 0000 0011 = 3
Example of C Bitwise Operators
Here is a simple program that demonstrates C bitwise operators:
47
/* Purpose: Demonstrates C bitwise operators */
#include <stdio.h>
void main() {
int d1 = 4, /* binary 101 */
d2 = 6, /* binary 110 */
d3;
printf("\nd1=%d", d1); printf("\nd2=%d",
d2);
d3 = d1 & d2; /* 0101 & 0110 = 0100 (=4) */
printf("\n Bitwise AND d1 & d2 = %d", d3); d3 =
d1 | d2; /* 0101 | 0110 = 0110 (=6) */
48
Note:- The receiving variable(LHS) should be present in the RHS expression.
So beside = operator, +=,- =, /=, %= , *= are used and they are called shorthand operators.
49
3.3.7 INCREMENT AND DECREMENT OPERATORS
In C, ++ and -- are called increment and decrement operators respectively. Both of theseoperators are
unary operators, i.e, used on single operand. ++ adds 1 to operand and -- subtracts 1from operand
respectively. For example:
Let a=5 and b=10
a++; //a becomes 6
a--; //a becomes 5
++a; //a becomes 6
--a; //a becomes 5
These operators can be placed as a prefix or post fix as below: a++;
++a;
When used on their own (as above) the prefix and postfix have the same effect BUT within an expression there
is a subtle difference....
1. Prefix notation will increment the variable BEFORE the expression is evaluated.
2. Postfix notation will increment AFTER the expression evaluation.
Here is an example:
main () main()
{ {
int a=1; int a=1;
printf(" a is %d", ++a); printf(" a is %d", a++);
} }
In both examples, the final value of a will be 2. BUT the first example will print 2 and the second will
print 1.
50
When a++ is used as prefix (like: ++var), ++var will increment the value of var and then return it but, if
++ is used as postfix(like: var++), operator will return the value of operand first and then only increment
it.
If the test condition is true, expression1 is returned and if false expression2 is returned.
Output:
10
#include<stdio.h>
51
Void main( )
int a, b,c;
scanf(“%d%d”,&a,&b);
printf(“%d”, c);
52
char is: 1 bytes
float is: 4 bytes
53
Void main( )
{
Float x=5.5,y=6.2;
Printf(“result is %5d\n”,(int)(x+y));
}
Output is:
Result is 11
3.3.11 EXPRESSION
Every expression consists of at least one operand and can have one or more operators. Operands are
values, whereas operators are symbols that represent particular actions. In the expression
x+5
x and 5 are operands, and + is an operator.
Expressions are often classified by the type of value that they represent.
Boolean expressions : Evaluate to either TRUE or FALSE
Arithmetic expressions: Expression involving arithmetic
operators Integer expressions: Evaluate to whole numbers, like 3
or 100
If more than one operator is involved in an expression then, C language has predefinedrule of
priority of operators. This rule of priority of operators is called operator precedence.
In C, precedence of arithmetic operators(*,%,/,+,-) is higher than relational operators(==,!=,>,<,>=,<=)
and precedence of relational operator is higher than logical operators(&&, || and !). Suppose an
expression:
(a>b+c&&d)
This expression is equivalent to: ((a>(b+c))&&d)
54
1. As it scans the expression from left to right, it comes across >, + and &&
symbols and among them + has highest priority so (b+c)is evaluated first
2. Then it performs a > result of 1
3. Result of 2 && d is executed at the end.
Associativity of operators:-
Associativity indicates in which order two operators of same precedence(priority) executes. Let
us suppose an expression:
a==b!=c
Here, operators == and != have same precedence. The associativity of both
== and != is left to right, i.e, the expression in left is executed first and execution takes place
towards right. Thus, a==b!=c equivalent to :
(a==b)!=c
The table below shows all the operators in C with precedence (highest to lowest) and associativity.
Associativity indicates in what order operators of equal precedence in an expression are applied.
*/ % Multiplication/division/modulus left-to-right
+ - Addition/subtraction left-to-right
55
< <= Relational less than/less than or equal to left-to-right
> >= Relational greater than/greater than or equal to
|| Logical OR left-to-right
= Assignment right-to-left
+= -= Addition/subtraction assignment
*= /= Multiplication/division assignment
%= &= Modulus/bitwise AND assignment
^= |= Bitwise exclusive/inclusive OR assignment
<<= >>= Bitwise shift left/right assignment
56
All C standard library functions are declared by using many header files. These library functions are
created at the time of designing the [Link] include the header files in our C program by using
#include<filename.h>. Whenever the program is run and executed, the related files are included in the C
program.
stdio.h − It is a standard i/o header file in which Input/output functions are declared
conio.h − This is a console input/output header file.
string.h − All string related functions are in this header file.
stdlib.h − This file contains common functions which are used in the C programs.
math.h − All functions related to mathematics are in this header file.
time.h − This file contains time and clock related [Link] functions in stdio.h
Advantages of Using C library functions
1. They work
One of the most important reasons you should use library functions is simply because they work. These
functions have gone through multiple rigorous testing and are easy to use.
57
4. The functions are portable
With ever-changing real-world needs, your application is expected to work every time, everywhere. And,
these library functions help you in that they do the same thing on every computer.
To compute the square root of a number, you can use the sqrt() library function. The function is defined
in the math.h header file.
#include <stdio.h>
#include <math.h>
int main()
{
float num, root; printf("Enter
a number: "); scanf("%f",
&num);
Enter a number: 12
Square root of 12.00 = 3.46
58
an expression more than one data type is present. In such condition type conversion (type promotion)
takes place to avoid loss of data.
All the data types of the variables are upgraded to the data type of the variable with largest data type.
bool -> char -> short int -> int ->
unsigned int -> long -> unsigned ->
long long -> float -> double -> long double
when signed is implicitly converted to unsigned, the signs may be lost and overflow can occur when long
long is implicitly converted to float.
The syntax in C:
59
(type) expression
Type indicated the data type to which the final result is converted.
double x = 1.2;
// Explicit conversion from double to int int
sum = (int)x + 1;
printf("sum = %d", sum); return
0;
}
Output:
sum = 2
Advantages of Type Conversion
3.6 SUMMARY
In this unit, you have studied the different types of operators available in [Link] hierarchy of evaluation of
these operators in an expression when two or more operators are included is explain in this unit.
Assignment statement is the simple statement; assigning value to variables is done by two ways. One
during declaration of variable itself and other way of assigning value is by using assignment statement.
Implicit and explicit type conversions are explained.
3.7 KEYWORDS
assignment statement
assignment operator
conditional operator
increment
60
3.8 QUESTIONS FOR SELF STUDY
3.9 REFERENCES
61
UNIT – 4: CONTROL STRUCTURES
Structure
4.0 Objectives
4.1 Introduction
4.2 Goto statement
4.3 If statement and if-else statement
4.4 Nesting of if statement
4.5 Switch statement
4.6 While and do-while loop
4.7 For loop
4.8 Break and continue statement
4.9 Summary
4.10 Keywords
4.11 Questions for self-study
4.12 Reference
4.0 OBJECTIVES
62
4.1 INTRODUCTION
In this unit we will go through some control statements and decision-making condition. Generally, C
program statement is executed in the order in which the program was appearing, but sometimes we should
use decision making condition for execution only a part of program, which is called control statement.
Control statement defined how the control is transferred from one part to the other part of the program. There
several control statement like goto, if...else, switch, while, do while, for loop, break, continue and nesting of
if etc.
A goto statement in C programming language provides an unconditional jump from the goto to a labeled
statement in the same function.
goto.
Syntax:
goto label; label:
statement;
The label can be any plain text except C keyword and also it can be set anywhere in the C program
above or below to goto statement.
63
Example: #include
<stdio.h>int main
()
{
int x = 10;
LOOP: do
{
if( x == 15)
{
x = x + 1;
goto LOOP;
}
printf("value of x: %d\n", x); x++;
}while( x < 20 );
return 0;
When the above code is compiled and executed, it produces the following result: value
of x: 10
value of x: 11
value of x: 12
value of x: 13
value of x: 14
value of x: 16
value of x: 17
value of x: 18
value of x:
64
4.3 IF STATEMENT AND IF-ELSE STATEMENT
If Statement:
If statement is decision making statement, here a single condition is to be checked. The condition enclosed
in if statement decides the sequence of execution of instruction. If the condition is true, the statements
inside if statement are executed, otherwise they are skipped. In C programming language, any non-zero
value is considered as true and zero or null is considered false.
65
Syntax:
If(condition)
{
True statements;
}
The statement is executed only when condition is true. If the if statement body is consists of several
statement then better to use pair of curly braces. If the condition is false then compiler skip the line within
the if block.
Example:
#include<stdio.h>
#include<conio.h> void
main()
{
int x;
printf (“ enter a number:”\n);
scanf(“%d”,&x);
If (x>20)
Printf(“ number is greater”);
}
Output:
Enter a number:22
Number is greater
66
If-Else statement:
The If-else statement is a two-way branching statement. It consists of two blocks of statements if block
and else block enclosed inside the If-else statement. If the condition inside statement is true, statements
inside if block are executed, otherwise statements inside the else block are executed. Else block is
optional and it may be absent in a program.
Syntax:
if (condition)
67
{
True Statement;
}
Else
{
False Statement;
}
Example:
#include<stdio.h>
#include<conio.h>
int main()
{
int x;
printf (“enter a number:”);
scanf (“%d”, &x);
If (x<40)
{
printf (“the value is less than 40”);
}
Else
{
printf(“the value is greater than 40”);
Return 0;
68
4.4 NESTING OF IF STATEMENT
In nested-if statement the if statement placed inside another if statement. Nested if statements are usually
used when you have to test a combination of conditions before deciding on the proper action.
Syntax:
The syntax for a nested if statement is as follows:
if( Condition 1)
{
if(Condition 2)
{
Statement block2;
}
}
We can nest else if...else in the similar way as you have nested if statement. When nested if— else is
used, else is combined with its immediate above if statement.
Conditi
False
True
Condit
False
True
Statement block2
Next statement
Fig 4.4.1 : Shows flowchart of Nesting of if statements
69
Example:
#include<stdio.h>
void main()
{
int x=100,y=200;
if(x==100)
{
if(y==200)
{
printf("value of x is 100, and value of y is 200.");
}
}
}
Output:
The switch statement in c contained multiple cases with break. The switch statements in c test the value of
a variable and compare it with multiple cases. if the case match is found means a block of statement
associated with that particular case is executed. Every case in a block of a switch has a unique
name/number which is referred to as an identifier. The value provided by the user is compared with all the
cases inside the switch block till the match is found. If a case match is NOT found, then the default
statement is executed, and the control goes out of the switch block.
70
Fig 4.5.1: Shows flowchart of switch statement
Syntax:
Switch (choice )
{
case 1:
statement 1;
break;
71
case 2:
statement 2;
break;
case 3:
statement 3;
break;
case n:
statement n;
}
Example:
void main()
{
int a;
printf("Please choose your favorite color(1:red,2:green,3:blue,4:yellow,5:white)\n "); scanf("%d",&color);
switch(a)
{
case 1:
printf("red color");
break;
case 2:
printf("green color"); break;
72
case 3:
printf("blue color");
break;
case 4:
printf("yellow color");
break;
case 5:
printf("white color"); break;
default:
printf("You’ve entered a wrong choice"); break;
}
Loops in C
Loop: -This is a block of statement that will perform a set of instructions. In loops repeating particular
portion of the program either a specified number of times or until a particular number of conditions is
satisfied.
While loop
Syntax: -
73
while(condition)
Statement 1;
Statement 2;
The test condition can be any expression. when we wish to do something a fixed number of times but not
knowing about the number of iteration, in a program then while loop will be [Link] first condition is
checked and if it is true then body of the loop is executed else, control will be come out of loop.
Example: -
Output: Welcome to C
Welcome to C
Welcome to C
Welcome to C
Welcome to C
So as long as condition remains true statements within the body of while loop willget executed
repeatedly.
Do while loop
This (do while loop) statement is also used for looping. The body of this loop may
74
contain single statement or block of statement. The syntax for writing this statement is: Syntax:
-
Do
Statement;
while(condition);
Example:
#include
<stdioh.h>
Int main ()
Int j=0;
do
{
Printf (“value of variable j is: %d\n”, j);
Output:
Here firstly statement inside body is executed then condition is checked. If the condition is true
again body of loop is executed and this process continue until the condition becomes false.
Unlike while loop semicolon is placed at the end of while. There is minor difference between
while and do while loop, while loop test the condition before executing any of the statement of
loop. Whereas do while loop test condition after having executed the statement at least one
within the loop. If initial condition is false while loop would not executed it’s statement on other
hand do while loop executed it’s statement at least once even If condition fails for first time. It
means do while loop always executes at least once.
75
4.7 FOR LOOP
A loop is used for executing a block of statements repeatedly until a given condition returns false.
Step 1: First initialization happens and the counter variable gets initialized.
Step 2: In the second step the condition is checked, where the counter variable is tested for the given
condition, if the condition returns true then the C statements inside the body of for loop gets executed, if
the condition returns false then the for loop gets terminated and the control comes out of the loop.
Step 3: After successful execution of statements inside the body of loop, the counter variable is incremented or
decremented, depending on the operation (++ or –).
76
Syntax:-
for(exp1;exp2;exp3)
Statement;
}
or
Statement;
Example:
#include <stdio.h> int main()
{
int i;
for (i=1; i<=3; i++)
{
printf("%d\n", i);
Output:
1
2
77
4.8 BREAK AND CONTINUE STATEMENT
Sometimes it becomes necessary to come out of the loop even before loop condition
becomes false then break statement is used. Break statement is used inside loop and switch
statements. It causes immediate exit from that loop in which it appears and it is generally
written with condition. It is written with the keyword as break. When break statement is
encountered loop is terminated and control is transferred to the statement, immediately after
loop or situation where we want to jump out of the loop instantly without waiting to get
back to conditional state. When break is encountered inside any loop, control automatically
passes to the first statement after the loop. This break statement is usually associated with if
statement.
Output:
78
Continue statement (key word continue)
Continue statement is used for continuing next iteration of loop after skipping some
statement of loop. When it encountered control automatically passes through the beginning
of the loop. It is usually associated with the if statement. It is useful when we want to
continue the program without executing any part of the program. The difference between
break and continue is, when the break encountered loop is terminated and it transfer to the
next statement and when continue is encounter control come back to the beginning position.
In a while and do while loop after continue statement control transfer to the test condition
and then loop continue where as in, for loop after continue control transferred to the updating
expression and condition is tested.
if ( a % 2 == 0 ) continue;
sum = sum + a;
}
printf("sum = %d",sum); return 0;
79
4.9 SUMMARY
In this unit we have introduced the concept of goto statement, if statement, if-else statement and
nested if statement. We also discussed switch statement, while and do-while loops along with
examples are given in their sections. At the end of this unit reader are able to figure out the concept of
for loop, break and continue statements which are available in C.
4.10 KEYWORDS
Syntax,
break,
switch,
goto,
4.11 QUESTIONS
1. Explain if-else statement with flowchart.
2. With example explain nested if statement.
3. Write a Flowchart of switch statement with an example.
4. Describe difference between while and do-while loop.
5. Discuss continue and break statement.
6. Write a program explain for loop.
4.12 REFERENCES
80
Unit – 5 FUNCTIONS
Structure
5.0 Objectives
5.1 Introduction
5.2 Graphical Representation
5.3 The Need for a Function
5.4 Types of C Function
5.10 Reference
5.0 OBJECTIVES
After going through this lesson, you will be able to
5.1 INTRODUCTION
A number of statements grouped into a single logical unit are called a function. The use of function
makes programming easier since repeated statements can be grouped into functions. Splitting the
program into separate function make the program more readable and maintainable. It is necessary to
have a single function ‘main’ in every C program, along with other functions used/defined by the
programmer. A function definition has two principal components: the function header and body of the
function. The function header is the data type of return value followed by function name and
(optionally) a set of arguments separated
81
by commas and enclosed in parenthesis. Associated type to which function accepts precedes each
argument. In general terms function header statement can be written as
where return_type represents the data type of the item that is returned by the function, function_name
represents the name of the function, and type1,type2,…,typen represents the data type of the
arguments arg1,arg2,..,argn.
Here p and q are arguments. The arguments are called formal arguments or formal parameters,
because they represent the name of the data item that is transferred into the function from the calling
portion of the program. The corresponding arguments in the function call are called actual arguments
or actual parameters, since they define the data items that are actually transferred. A function can be
invoked whenever it is needed. It can be accessed by specifying its name followed by a list of
arguments enclosed in parenthesis and separated by commas. e.g., add(5,10);
The number of arguments in the function calls and function declaration must be same.
The prototype of each of the argument in the function call should be same as the
corresponding parameter in the function declaration statement.
For example, the code shown below illustrate how function can be used in programming
//C Program for Addition of Two Number's using User Define Function
#include<stdio.h>
82
#include<conio.h>
float a,b,c;
clrscr();
printf("Enter the value for a & b\n\n"); scanf("%f
%f",&a,&b);
c=add(a,b);
printf("\nc=%f",c); getch();
}
float z; z=x+y;
return(z);
}
Graphical Representation is a way of analyzing numerical data. It exhibits the relation between data,
ideas, information and concepts in a diagram. It is easy to understand and it is one of the most
important learning strategies. It always depends on the type of information in a particular domain.
There are different types of graphical representation. Some of them are as follows:
Line Graphs – Line graph or the linear graph is used to display the continuous data and it is
useful for predicting future events over time. Fig:5.2.1
83
Bar Graphs – Bar Graph is used to display the category of data and it compares the data
using solid bars to represent the quantities. Fig:5.2.2
Histograms – The graph that uses bars to represent the frequency of numerical data that
are organized into intervals. Since all the intervals are equal and continuous, all the bars
have the same width. Fig:5.2.3
Line Plot – It shows the frequency of data on a given number line. ‘ x ‘ is placed above a
number line each time when that data occurs [Link].2.4
84
Frequency Table – The table shows the number of pieces of data that falls within the
given interval. Fig:5.2.5
Circle Graph – Also known as the pie chart that shows the relationships of the parts of the
whole. The circle is considered with 100% and the categories occupied is represented
with that specific percentage like 15%, 56%, etc. Fig:5.2.6
Stem and Leaf Plot – In the stem and leaf plot, the data are organized from least value to
the greatest value. The digits of the least place values from the leaves and the next place
value digit forms the stems. Fig:5.2.7
85
Box and Whisker Plot – The plot diagram summarizes the data by dividing into four
parts. Box and whisker show the range (spread) and the middle (median) of the data.
Fig:5.2.8
o Suitable Title: Make sure that the appropriate title is given to the graph which indicates
the subject of the presentation.
o Measurement Unit: Mention the measurement unit in the graph.
o Proper Scale: To represent the data in an accurate manner, choose a proper scale.
o Index: Index the appropriate colors, shades, lines, design in the graphs for better
understanding.
o Data Sources: Include the source of information wherever it is necessary at the
bottom of the graph.
o Keep it Simple: Construct a graph in an easy way that everyone can understand.
o Neat: Choose the correct size, fonts, colors etc. in such a way that the graph should be
a visual aid for the presentation of information.
86
Graphical Representation in Math’s
In Mathematics, a graph is defined as a chart with statistical data, which are represented in the form
of curves or lines drawn across the coordinate point plotted on its surface. It helps to study the
relationship between two variables where it helps to measure the change in the variable amount with
respect to another variable within a given interval of time. It helps to study the series distribution and
frequency distribution for a given problem. There are two types of graphs to visually depict the
information. They are:
Algebraic principles are applied to all types of graphical representation of data. In graphs, it is
represented using two lines called coordinate axes. The horizontal axis is denoted as the x- axis and
the vertical axis is denoted as the y-axis. The point at which two lines intersect is called an origin
‘O’. Consider x-axis, the distance from the origin to the right side will take a positive value and the
distance from the origin to the left side will take a negative value.
Similarly, for the y-axis, the points above the origin will take a positive value, and the points below the
origin will a negative value. Fig:5.2.9
o Histogram
87
o Smoothed frequency graph
o Pie diagram
o Cumulative or ogive frequency graph
o Frequency Polygon
o Obtain the frequency distribution and find the midpoints of each class interval.
o Represent the midpoints along x-axis and frequencies along the y-axis.
o Plot the points corresponding to the frequency at each midpoint.
o Join these points, using lines in order.
o To complete the polygon, join the point at each end immediately to the lower- or
higher-class marks on the x-axis.
88
5.3 The Need for Function
Functions are very much required in hard core programming because of many reasons. Here we list
out most common necessity for function requirement: Functions can be executed as many times as
necessary from different points in a program. Without the ability to package a block of code
into a function, programs would end up being much larger, since you would typically need to
replicate the same code at various points in your program. But the real reason that you need
functions is to modularize your program into easily manageable chunks. Functions allow a
program to be segmented so that it can be written piecemeal, and each piece tested
independently before bringing it together with the other pieces. It also allows the work to be
divided among members of a programming team, with each team member taking
responsibility for a tightly specified piece of the program, with a well-defined functional
interface to the rest of the code. Real-world large-scale programming projects are developed
using this approach
Library function
User defined function
Library functions are built-in functions that are grouped together and placed in a common location
called library. Each function here performs a specific operation. We can use this library functions to get
the pre-defined output. All are declared by using many header files. These library functions are created
at the time of designing the compilers. We include the header files in our C program by using
#include<filename.h>. Whenever the program is run and executed, the related files are included in the
C program.
o stdio.h − It is a standard i/o header file in which Input/output functions are declared
o conio.h − This is a console input/output header file.
o string.h − All string related functions are in this header file.
o stdlib.h − This file contains common functions which are used in the C programs.
o math.h − All functions related to mathematics are in this header file.
o time.h − This file contains time and clock related [Link] functions in stdio.h
89
For example:
main()
The execution of every C program starts from this main. prinf() is
printf()
used for displaying output in C.
scanf()
scanf() is used for taking input in C.
for further information about the library functions readers can look into help section of C
compiler and more library functions and their usage is discussed in forthcoming sections and
modules.
A function is a block of code that can be used to perform a specific action. C allows
programmers to write their own functions, also known as user-defined functions. A user-
defined function has three main components that are function declarations, function definition
and function call. Further functions can be called by call by value or call by reference.
Functions need to be written once and can be called as many times as required inside the
program, which increases reusability in code and makes code more readable and easier to test,
debug, and maintain the code.
C provides programmer to define their own function according to their requirement known as user
defined functions.
Example of how C function works
#include <stdio.h>
void
function_name(){
................
................
}
int main(){
...........
...........
function_name();
...........
90
...........
}
As mentioned earlier, every C program begins from main() and program starts executing the codes
inside main function. When the control of program reaches to function_name() inside main. The
control of program jumps to "void function_name()" and executes the codes inside it. When, all the
codes inside that user defined function is executed, control of the program jumps to statement just
below it. Analyze the figure below for understanding the concept of function in C. Fig 5.4.1
91
Example of user defined function
#include <stdio.h>
int add(int a, int b); //function
prototype(declaration)int main(){
int num1,num2,sum;
printf("Enters two number to add\n");
scanf("%d %d",&num1,&num2);
sum=add(num1,num2); //function
callprintf("sum=%d",sum);
return 0;
}
int add(int a,int b) //function declarator
{
/*line 13-19 is called function body
line 12-19 is called function definition.*/
int add;
add=a+b;
return add; //return statement of function
}
Here, in the above example, function prototype is "int add(int a, int b);" which provides
following information to the compiler:
1. name of the function is "add"
2. return type of the function is int.
3. two arguments of type int are passed to function.
92
Function prototype is not needed, if you write function definition above the main function. In this
program if the code from line 12 to line 19 is written above main( ), there is no need of function
prototype.
Control of the program cannot be transferred to user-defined function (function definition) unless
it is called (invoked).
Syntax of function call
function_name(argument(1),. argument(n));
In the above example, function call is made using statement "add(num1,num2);" in line 9. This
makes control of program transferred to function declarator (line 12). In line 8, the value returned
by function is kept into "sum" which you will study in detail in function return type of next unit.
Functions Arguments
Before the Standard, it was not possible to give any information about a function's arguments
except in the definition of the function itself. The information was only used in the body of the
function and was forgotten at the end. In those bad old days, it was quite possible todefine a
function that had three double arguments and only to pass it one int, when it was called. The
program would compile normally, but simply not work properly. It was considered to be the
programmer's job to check that the number and the type of arguments toa function matched
correctly. As you would expect, this turned out to be a first-rate source of bugs and portability
problems. Here is an example of the definition and use of a function witharguments, but omitting
for the moment to declare the function fully.
#include
<stdio.h>
#include
<stdlib.h>
main(){
pmax(i,j);
93
}
}
exit(EXIT_SUCCES
S);
}
/*
* Function pmax.
* Returns: void
* Prints larger of its two arguments.
*/
vo
id
}
To start with, notice the careful declaration that pmax returnsvoid. In the function definition, the
matching void occurs on the line before the function name. The reason for writing it like that is
purely one of style; it makes it easier to find function definitions if their names are always at the
beginning of a line.
The function declaration (in main) gave no indication of any arguments to the function, yet the use
of the function a couple of lines later involved two arguments. That is permitted by both the old
and Standard versions of C, but must nowadays be considered to be bad practice. It is much
better to include information about the arguments in the declaration too, as we will see. The old
style is now an ‘obsolescent feature’ and may disappear in a later version of the Standard.
Now on to the function definition, where the body is supplied. The definition shows that the
94
function takes two arguments, which will be known as a1 and a2 throughout the body of the
function. The types of the arguments are specified too, as can be seen.
In the function definition you don't have to specify the type of each argument because they will
default to int, but this is bad style. If you adopt the practice of always declaring arguments, even if
they do happen to be int, it adds to a reader's confidence. It indicates that
you meant to use that type, instead of getting it by accident: it wasn't simply forgotten. The
definition of pmax could have been this:
/* and so on */
The proper way to declare and define functions is through the use of prototypes.
Arguments can be passed to a function by two methods, they are called passing by value and
passing by reference. When a single value is passed to a function via an actual argument, the value
of the actual argument is copied into the function. Therefore, the value of the corresponding formal
argument can be altered within the function, but the value of the actual argument within the calling
routine will not change. This procedure for passing the value of an argument to a function is known
as passing by value.
{
int x=3;
printf(“\n x=%d(from main, before calling the
function”),x);
change(x);
printf(“\n\nx=%d(from main, after calling
thefunction)”,x);
}
change(x) int x;
{
x=x+3;
printf(“\nx=%d(from the function, after
beingmodified)”,x);
95
return;
}
The original value of x (i.e. x=3) is displayed when main begins execution. This value is then
passed to the function change, where it is sum up by 3 and the new value displayed. This new value
is the altered value of the formal argument that is displayed within the function. Finally, the value
of x within main is again displayed, after control is transferred back to mainfrom change.
The return statement is very important. Every function except those returning void should have at
least one, each return showing what value is supposed to be returned at that point. Although it is
possible to return from a function by falling through the last }, unless the function returns void an
unknown value will be returned, resulting in undefined behavior.
Here is another example function. It uses getchar to read characters from the program input and
returns whatever it sees except for space, tab or newline, which it throws away.
96
#include <stdio.h>
int non_space(void)
{
int c;
while ( (c=getchar ())=='\t' || c== '\n' || c==' ')
; /* empty statement */ return
(c);
}
Look at the way that all of the work is done by the test in the while statement, whose body was an
empty statement. It is not an uncommon sight to see the semicolon of the empty statement sitting
there alone and forlorn, with only a piece of comment for company and readability. Please, please,
never write it like this:
while (something);
with the semicolon hidden away at the end like that. It's too easy to miss it when you read the code,
and to assume that the following statement is under the control of the while.
The type of expression returned must match the type of the function, or be capable of being
converted to it as if an assignment statement were in use. For example, a function declared to
return double could contain
return (1);
and the integral value will be converted to double. It is also possible to have just return without any
expression—but this is probably a programming error unless the function returns void. Following
the return with an expression is not permitted if the function returns void.
Nesting Function
A nested function is a function defined inside the definition of another function. It can be defined
wherever a variable declaration is permitted, which allows nested functions within nested
functions. Within the containing function, the nested function can be declared prior to being
defined by using the
A nested function can access all identifiers of the containing function that precede its definition.
A nested function must not be called after the containing function exits.
97
A nested function cannot use a goto statement to jump to a label in the containing function, or to a
local label declared with the label keyword inherited from the containing function.
Although any name can be given to these parameters, they are usually referred toas argc
and argv. The first parameter, argc (argument count) is an integer that indicates how many
arguments were entered on the command line when the program was started. The second
parameter, argv(argument vector), is an array of pointers to arrays of character objects. The array
objects are null-terminated strings, representing the arguments that were entered on the command
line when the program was started.
The first element of the array, argv[0], is a pointer to the character array that contains the program
name or invocation name of the program that is being run from the command line. argv[1]
indicates the first argument passed to the program, argv[2] the second argument, and so on.
Recursion
With argument passing safely out of the way we can look at recursion. Recursion is a topic that often
provokes lengthy and unenlightening arguments from opposing camps. Some think it is wonderful,
and use it at every opportunity; some others take exactly the opposite view. Let's
98
just say that when you need it, you really do need it, and since it doesn't cost much toput into
a language, as you would expect, C supports recursion.
Every function in C may be called from any other or itself. Each invocation of a function causes a
new allocation of the variables declared inside it. In fact, the declarations that we have been using
until now have had something missing: the keyword auto, meaning ‘automatically allocated’.
/* Example of auto
*/ main(){
auto int var_name;
.
.
.
}
The storage for auto variables is automatically allocated and freed on function entry and return. If
two functions both declare large automatic arrays, the program will only have tofind room for
both arrays if both functions are active at the same time. Although auto is a keyword, it is never
used in practice because it's the default for internal declarations and is invalid for external ones. If
an explicit initial value isn't given for an automatic variable, then its value will be unknown when it is
declared. In that state, any use of its value will cause undefined behavior.
The real problem with illustrating recursion is in the selection of examples. Too often, simple
examples are used which don't really get much out of recursion. The problems where it really helps
are almost always well out of the grasp of a beginner who is having enough trouble trying to sort out
the difference between, say, definition and declaration without wanting the extra burden of having
to wrap his or her mind around a new concept as well. The chapter on data structures will show
examples of recursion where it is a genuinely useful technique.
The following example uses recursive functions to evaluate expressions involving single digit
numbers, the operators *, %, /, +, - and parentheses in the same way that C does. The whole
expression is evaluated and its value printed when a character not in the ‘language’ is read. For
simplicity no error checking is performed. Extensive use is made of the ungetc library function,
which allows the last character read by getchar to be ‘unread’ and become once again the next
character to be read. Its second argument is one of the things declaredin stdio.h.
99
The main places where recursion occurs are in the function unary_exp, which calls itself, and at the
bottom level where primary calls the top level all over again to evaluate parenthesized expressions.
Try running following piece of code for better understanding. Trace its actions by hand on inputs
such as
1
1+2
1+2 * 3+4
1+--4
1+(2*3)+4
#include <stdio.h>
#include <stdlib.h>
int expr(void);
int
mul_exp(void);
int
unary_exp(void);
int primary(void);
main(){
int val;
for(;;){
printf("expression: "); val =
expr(); if(getchar() != '\n'){
printf("error\n"); while(getchar() !=
'\n')
; /* NULL */
100
} else{
printf("result is %d\n", val);
}
} exit(EXIT_SUCCESS);
int
expr(voi
d){
val = mul_exp();
for(;;){
ungetc(ch_in,stdin); return(val);
case '+':
val = val + mul_exp(); break;
case '-':
val = val - mul_exp(); break;
}
}
}
int
mul_exp(voi
d){
101
int val, ch_in;
val = unary_exp();
for(;;){
case '*':
val = val * unary_exp(); break;
case '/':
val = val / unary_exp(); break;
case '%':
val = val % unary_exp(); break;
}
}
}
int
unary_exp(void
){
switch(ch_in = getchar()){
default:
102
ungetc(ch_in, stdin); val =
primary(); break;
case '+':
val = unary_exp(); break;
case '-':
val = -unary_exp(); break;
}
return(val);
}
int
primary(void
){
ch_in = getchar();
if(ch_in >= '0' && ch_in <= '9'){ val =
ch_in - '0';
goto out;
}
if(ch_in == '('){
val = expr();
getchar(); /* skip closing ')' */
goto out;
}
printf("error: primary read %d\n",
ch_in);exit(EXIT_FAILURE);
out:
return(val);
}
103
Every variable and function in C programming have two properties: type and storage class. Type
refers to the data type of variable whether it is character or integer or floating-point value etc.
There are 4 types of storage class:
o automatic
o external
o static
o register
External variable can be accessed by any function. They are also known as global variables.
Variables declared outside every function are external variables. In case of large program,
containing more than one file, if the global variable is declared in file 1 and that variable is used in
file 2 then, compiler will show error. To solve this problem, keyword extern is used in file 2 to
indicate that, the variable specified is global variable and declared in another file.
104
5.7 Summary
At the end of this unit, you have learnt about functions, how to define and declare functions,
what are the functions different data types. It has been also discussed about the library
functions and user defined functions. You are now able to execute function from different
places of a program.
5.8 Keywords
Function call
prototype
library function
used defined function
5.10 Reference
105
Unit-6 ARRAY
Structure
6.0 Objectives
6.1 Introduction: Basics of Array
6.2 Pointer Declaration
6.3 The & and * Operators
6.4 Passing Pointers to a Function
6.5 Operations on Pointers
6.6 Pointer Arithmetic
6.7 Summary
6.8 Key words
6.9 Questions for self-study
6.10 References
6.0 OBJECTIVES
106
What Is Array?
For instance, if you want to keep a record of the marks obtained by a student in 6 subjects,
then you don’t need to determine the variables individually. Rather, you can determine an
array that will store each piece of data factors at a contiguous memory location. Arrays are
one of the oldest and most essential data structures used in almost every program. Arrays
are also useful in implementing other data structures such as lists, heaps, hash tables,
deques, queues, stacks, and strings.
A pointer is a variable that contains the memory location of another variable. The syntax is as
shown below. We start by specifying the type of data stored in the location identified by the
pointer. The asterisk tells the compiler that we are creating a pointer variable. Finally we give
the name of the variable.
type * variable name;
Example:
int *ptr;
float *string;
Once we declare a pointer variable, we must point it to something we can do this by assigning
to the pointer the address of the variable we want to point as in the following example:
ptr=#
This places the address where num is stores into the variable ptr. If num is stored in memory
21260 address then the variable ptr has the value 21260.
107
/* A program to illustrate pointer declaration*/
main()
{
int *ptr;
int sum;
sum=45;
ptr=sum;
printf (“\n Sum is %d\n”, sum);
printf (“\n The sum pointer is %d”, ptr);
}
We will get the same result by assigning the address of num to a regular (non-pointer)
variable. The benefit is that we can also refer to the pointer variable as *ptr the asterisk tells to
the computer that we are not interested in the value 21260 but in the value stored in that
memory location. While the value of pointer is 21260 the value of sum is 45 however we can
assign a value to the pointer * ptr as in *ptr=45.
This means place the value 45 in the memory address pointer by the variable ptr. Since the
pointer contains the address 21260 the value 45 is placed in that memory location. And since
this is the location of the variable num the value also becomes 45. this shows how we can
change the value of pointer directly using a pointer and the indirection pointer.
The pointers are very much used in a function declaration. Sometimes only with a pointer a
complex function can be easily represented and success. The usage of the pointers in a
function definition may be classified into two groups.
1. Call by reference
2. Call by value
Call by value
We have seen that a function is invoked there will be a link established between the formal
and actual parameters.A temporary storage is created where the value of actual parameters is
stored. The formal parameters picks up its value from storage area the mechanism of data
transfer between actual and formal parameters allows the actual parameters mechanism of
data transfer is referred as call by value.
The corresponding formal parameter represents a local variable in the called function. The
current value of corresponding actual parameter becomes the initial value of formal
parameter. The value of formal parameter may be changed in the body of the actual
parameter. The value of formal parameter may be changed in the body of the subprogram by
108
assignment or input statements. This will not change the value of actual parameters.
/* Include< stdio.h >
void main()
{
int x,y;
x=20;
y=30;
printf(“\n Value of a and b before function call =%d %d”,a,b);
fncn(x,y);
printf(“\n Value of a and b after function call =%d %d”,a,b);
}
fncn(p,q)
int p,q;
{
p=p+p;
q=q+q;
}
Call by Reference
When we pass address to a function the parameters receiving the address should be pointers.
The process of calling a function by using pointers to pass the address of the variable is
known as call by reference. The function which is called by reference can change the values
of the variable used in the call.
/* example of call by reference*/
/* Include< stdio.h >
void main()
{
int x,y;
x=20;
y=30;
printf(“\n Value of a and b before function call =%d %d”,a,b);
fncn(&x,&y);
printf(“\n Value of a and b after function call =%d %d”,a,b);
}
fncn(p,q)
int p,q;
109
{
*p=*p+*p;
*q=*q+*q;
}
Pointer variables are not directly usable by many of the operators, functions, or procedures
provided by IDL. You cannot, for example, do arithmetic on them or plot them. You can, of
course, do these things with the heap variables referenced by such pointers, assuming that
they contain appropriate data for the task at hand. Pointers exist to allow the construction of
dynamic data structures that have lifetimes that are independent of the program scope they are
created in.
There are 4 IDL operators that work with pointer variables: assignment, dereference, EQ, and
NE. The remaining operators (addition, subtraction, etc.) do not make any sense for pointer
types and are not defined.
Many non-computational functions and procedures in IDL do work with pointer variables.
Examples are SIZE, N_ELEMENTS, HELP, and PRINT. It is worth noting that the only I/O
allowed directly on pointer variables is default formatted output, where they are printed as a
symbolic description of the heap variable they point at. This is merely a debugging aid for the
IDL programmer—input/output of pointers does not make sense in general and is not allowed.
Please note that this does not imply that I/O on the contents of non-pointer data held in heap
variables is not allowed. Passing the contents of a heap variable that contains non-pointer data
to the PRINT command is a simple example of this type of I/O.
Assignment
Assignment works in the expected manner—assigning a pointer to a variable gives you
another variable with the same pointer. Hence, after executing the statements:
A = PTR_NEW(FINDGEN(10))
B=A
HELP, A, B
A and B both point at the same heap variable and we see the output:
A POINTER= <PtrHeapVar1>
B POINTER= <PtrHeapVar1>
110
Dereference
In order to get at the contents of a heap variable referenced by a pointer variable, you must use
the dereference operator, which is * (the asterisk). The dereference operator precedes the
variable dereferenced. For example, if you have entered the above assignments of the
variables A and B:
PRINT, *B
IDL prints:
That is, IDL prints the contents of the heap variable pointed at by the pointer variable B.
To initialize this array such that the heap variable pointed at by the first pointer contains the
integer zero, the second the integer one, and the third the integer two, you would use the
following statement:
Note: The dereference operator is dereferencing only element I of the array for each iteration.
Similarly, if you wanted to print the values of the heap variables pointed at by the pointers in
ptarr, you might be tempted to try the following:
PRINT, *ptarr
IDL prints:
111
Dereferencing Pointers to Pointers
The dereference operator can be applied as many times as necessary to access data pointed at
indirectly via multiple pointers. For example, the statement:
A = PTR_NEW(PTR_NEW(47))
Assigns to A a pointer to a pointer to a heap variable containing the value 47.
To print this value, use the following statement:
PRINT, **A
Dereferencing Pointers within Structures
If you have a structure field that contains a pointer, dereference the pointer by prepending the
dereference operator to the front of the structure name. For example, if you define the
following structure:
you would use the following command to print the value of the heap variable pointed at by the
pointer in the pointer field:
PRINT, *[Link]
Defining pointers to structures is another common practice. For example, if you define the
following pointer:
ptstruct = PTR_NEW(struct)
you would use the following command to print the value of the heap variable pointed at by the
pointer field of the struct structure, which is pointed at by ptstruct:
PRINT, *(*pstruct).pointer
Note that you must dereference both the pointer to the structure and the pointer within the
structure.
PRINT, *45
112
IDL prints:
For example:
113
C NE NULL: 0
C has the speed and efficiency of assembly language combined with readability of assembly
language. In other words, it's just a glorified assembly [Link]'s perhaps too harsh a
judgment of C, but certainly one of the reasons the language was invented was to write
operating systems. Writing such code requires the ability to access addresses in memory in an
efficient manner. This is why pointers are such an important part of the C language. They're
also a big reason programmers have bugs.
If you're going to master C, you need to understand pointer arithmetic, and in particular, the
relationship between arrays and pointers.
Arbitrary Pointer Casting
Because most ISAs use the same number of bits as integers, it's not so uncommon to cast
integers as pointers.
Here's an example.
// Casting 32 bit int, 0x0000ffff, to a pointer
char * ptr = reinterpret_cast<char *>( 0x0000ffff ) ;
char * ptr2 = reinterpret_cast<char *>( 0x0000ffff ) ;
In general, this is one of the pitfalls of C. Arbitrary pointer casting allows you to point
anywhere in [Link], this is not good for safe programs. In a safe
programming language (say, Java), the goal is to access objects from pointers only when
there's an object there. Furthermore, you want to call the correct operations based on the
object's type.
Arbitrary pointer casting allows you to access any memory location and do anything you want
at that location, regardless of whether you can access that memory location or whether the
data is valid at that memory location.
6.6 POINTERS AND ARRAYS
114
Let's take a closer look at arr + i. What does that mean? arr is a pointer to arr[ 0 ]. In fact, it is
defined to be & arr[ 0 ].
A pointer is an address in memory. arr contains an address in memory---the address
where arr[ 0 ] is located.
What is arr + i? If arr is a pointer to arr[ 0 ] then arr + i is a pointer to arr[ i ].
Perhaps this is easier shown in a diagram. Fig 6.5.1
We assume that each int takes up 4 bytes of memory. If arr is at address 1000, then arr + 1 is
address 1004, arr + 2 is address 1008, and in general, arr + i is address 1000 + (i * 4).Now that
you see the diagram, something may strange. Why is arr + 1 at address 1004 and not 1001?
That's pointer arithmetic in action. arr + 1 points to one element past arr. arr + 3 is points to 3
elements past arr. Thus, arr + i points to i elements past [Link] idea is to have arr + i point
to i elements after arr regardless of what type of element the array [Link] the array
had contained short where a short is only 2 bytes. If arr is at address 1000, then, arr + 1 is
address 1002 (instead of 1004). arr + 2 is at address 1004 (instead of 1008), and in general arr
+ i is at address 1000 + (2 * i). Fig 6.5.2
Notice that arr + 1 is now 2 bytes after arr and arr + 2 is 4 bytes. When we had an int array, arr
+ 1 was 4 bytes after arr and arr + 2 was 8 bytes afterwards.
Why is there a difference? What's the difference between arr before and now?
The difference is in the type. Before, arr had (roughly) type int * and now arr has type short *.
In C, a pointer is not only an address, it tells you what (in principle) the data type at that
address is. Thus, int * is a pointer to an int. Not only does it tell you the data type, but you can
also determine the data type's [Link] can find out the data type's size with
the sizeof() operator.
115
sizeof( int ) ==> 4
sizeof( short ) ==> 4
That's important, because that's how pointer arithmetic computes address. It uses the size of
the data type, which it knows from the pointer's [Link]'s the formula for computing the
address of ptr + i where ptr has type T *. then the formula for the address is:
addr( ptr + i ) = addr( ptr ) + [ sizeof( T ) * i ]
T can be a pointer
How does pointer arithmetic work if you have an array of pointers, for example:
int * arr[ 10 ] ;
int ** ptr = arr ;
In this case, arr has type int **. Thus, T has type int *. All pointers have the same size, thus
the address of ptr + i is:
addr( ptr + i ) = addr( ptr ) + [ sizeof( int * ) * i ]
= addr( ptr ) + [ 4 * i ]
Static arrays are constant
When you declare
int arr[ 10 ] ;
arr is a constant. It is defined to be the address, & arr[ 0 ].
You can't do the following:
int arr[ 10 ] ;
116
Thus, it becomes arr becomes a pointer variable.
Why doesn't this cause problem? After all, won't we pass arr as an argument? Isn't arr a
constant?
Yes, it is. However, we pass a copy of the address to arr the parameter. Thus, the copy can be
manipulated while the original pointer address that was passed during the function call is
unchanged.
Subtraction
We can also compute ptr - i. For example, suppose we have an int array called arr.
int arr[ 10 ] ;
int * p1, * p2 ;
int arr2[ 10 ] ;
117
// Prints 40
cout << sizeof( arr2 ) ;
}
If you declare a local array (not using dynamic memory allocation), you can get the size of the
array. However, once you pass that array, all that's passed is the address. There's no
information about the array size anymore.
118
When you have a 2D array as a parameter to a function, there's no need to specify the number
of rows. You just need to specify the number of columns. The reason is the formula above.
The compiler can compute the address of an element in a 2D array just knowing the number
of columns.
Thus, the following is valid in C, i.e. it compiles:
void sumArr( int arr[][ COLS ], int numRows, int numCols ) {
}
The following is also valid in C.
void sumArr( int arr[ ROWS ][ COLS ], int numRows, int numCols ) {
}
The compiler ignores ROWS. Thus, any 2D array with the COLS columns and any number of
rows can be passed to this function.
The following, however, is NOT valid in C:
void sumArr( int arr[][], int numRows, int numCols ) {
}
It's not syntactically valid to declare int arr[][] in C.
However, it's OK to write:
void sumArr( int **arr, int numRows, int numCols ) {
}
Note that int **arr is an array of pointers (possibly to 1D arrays), while int arr[][ COLS ] is a
2D array. They are not the same type, and are not interchangeable.
Pointer Subtraction
It turns out you can subtract two pointers of the same type. The result is the distance (in array
elements) between the two elements.
For example:
int arr[ 10 ] ;
int * p1 = arr + 2 ;
int * p2 = arr + 5 ;
119
when p2 and p1 contain invalid addresses (because they contain some address).
Pointer subtraction isn't used very much, but can be handy to determine the distances between
two array elements (i.e., the difference in the array indexes). You may not know exactly
which element you're pointing to using pointer subtraction, but you can tell relative distances.
6.7 SUMMARY
At the end of this unit, we have covered the topics such as basic terminology of pointer. It has
been clearly given about how the pointer variables can be declared and how it can visualize
with a suitable example. In subsequent stages we have discussed about the role of & and *
operators.
6.8 KEYWORDS
120
UNIT – 7 STRINGS
Structure
7.0 Objectives
7.1 Introduction
7.2 Declaration and Initialization of String
7.3 Reading String from Terminal
7.4 Writing String to screen
7.5 Arithmetic Operations on String
7.6 String Handling Function
7.7 Summary
7.8 Key words
7.9 Questions for self-study
7.10 References
7.0 OBJECTIVES
7.1 STRINGS
In C, array of character are called strings. A string is terminated by null character /0. For
example:
"c string unit"
Here, "c string unit" is a string. When, compiler encounters strings, it appends null character
at the end of string.
Strings are useful for communicating information from the program to the program user and,
thus are a part of all programming languages and applications. They are implemented
121
with characters arrays that behave like usual arrays with which we can perform regular
operations, including modification. Another way of implementing strings is
through pointers since character arrays act as pointers. These pointers point to string literals
and cannot be modified as string literals are stored in the read-only memory by most
compilers. Thus, any attempt at modifying them leads to undefined behavior.
Strings is declared in C in similar manner as arrays. Only difference is that, strings are
of char type.
char s[5];
Initialization of strings
In C, string can be initialized in different number of ways.
char c[]="abcd";
OR,
char c[5]="abcd";
OR,
char c[]={'a','b','c','d','\0'};
OR;
char c[5]={'a','b','c','d','\0'};
#include <stdio.h>
int main(){
char name[30],ch;
int i=0;
printf("Enter name: ");
while(ch!='\n') //terminates if user hit enter
{
ch=getchar();
name[i]=ch;
i++;
}
name[i]='\0'; //inserting null character at end
printf("Name: %s",name);
return 0;
}
This process to take string is tedious. There are predefined functions gets() and puts in C
language to read and display string respectively.
123
#include<stdio.h>
int main(){
char name[30];
printf("Enter name: ");
gets(name); //Function to read string from user.
printf("Name: ");
puts(name); //Function to display string.
return 0;
}
Both, the above program have same output below:
Output
Enter name: Anil Ross
Name: Anil Ross
Passing Strings to Functions
String can be passed in similar manner as arrays as, string is also an array (of characters).
#include <stdio.h>
void Display(char ch[]);
int main(){
char c[50];
printf("Enter string: ");
gets(c);
Display(c); //Passing string c to function.
return 0;
}
void Display(char ch[]){
printf("String Output: ");
puts(ch);
}
Here, string c is passed from main() function to user-defined function Display(). In function
declaration in line 10, ch[] is the formal argument. It is not necessary to give the size of array
in function declaration.
To write strings to the terminal, we use a file stream known as stdout. The most common
124
function to use for writing to stdout in C is the printf function, defined as follows:
Sample Code
int printf(const char *format, ...);
To print out a prompt for the user you can:
Sample Code
printf("Please type a name: \n");
The above statement prints the prompt in the quotes and moves the cursor to the next line.
If you wanted to print a string from a variable, such as our fname string above you can do this:
Sample Code
printf("First Name: %s", fname);
You can insert more than one variable, hence the "..." in the prototype for printf but this is
sufficient. Use %s to insert a string and then list the variables that go to each %s in your string
you are printing. It goes in order of first to last. Let's use a first and last name printing
example to show this:
Sample Code
printf("Full Name: %s %s", fname, lname);
The first name would be displayed first and the last name would be after the space between
the %s's.
Characters in C can be used just like integers when used with arithmetic operators. This is
nice, for example, in low memory applications because unsigned chars take up less memory
than do regular integers as long as your value does not exceed the rather limited range of an
unsigned char.
For example: consider the following piece of code
charmath.c:
#include <stdio.h>
void main() {
unsigned char val1 = 20;
unsigned char val2 = 30;
int answer;
125
printf("%d\n", val1);
printf("%d\n", val2);
val1 = 'a';
answer = val1 + val2;
First we make two unsigned character variables and give them number values. We then add
them together and put the answer into an integer variable. We can do this without a cast
because characters are an alphanumeric data type. Next we set var1 to an expected character
value, the letter lowercase a. Now this next addition adds 97 to 30.
This is because the ASCII value of lowercase a is 97. So it adds 97 to 30, the current value in
var2. Notice it did not require casting the characters to integers or having the compiler
complain. This is because the compiler knows when to automatically change between
characters and integers or other numeric types.
One can perform different type of string operations manually like: finding length of string,
concatenating (joining) two strings etc. But this process is tedious. To perform these
operations, there are different library functions.
126
Function Work Of Function
Strings handling functions are defined under "string.h" header file, i.e, you have to include the
code below to run string handling functions.
#include <string.h>
Example to show how to "string.h" header file
#include <stdio.h>
#include <string.h>
int main(){
char s[]="Programiz";
int length;
length=strlen(s); /* Compiler will show error if you
use
this statement without using code #include <string.h>
in line number 2*/
printf("%d",length);
return 0;
}
#include<stdio.h>
int main(){
char name[30];
printf("Enter name: ");
gets(name); //Function to read string from user.
127
printf("Name: ");
puts(name); //Function to display string.
return 0;
}
Though, gets() and puts() function handle string, both these functions are defined in "stdio.h"
header file.
7.7 SUMMARY
In this unit we have introduced string operations which are supported in C programming. We
have seen how strings can be declared and initialized. Later we have seen an example how to
read and write the string from terminal and to screen respectively. At the end the section we
have list out some standard library function in support of string operations.
7.8 KEYWORDS
String,
char,
strlen,
strrev,
7.10 REFERENCES
Programming In ANSI C by E Balagurusamy
The C Programming Language (Ansi C Version) by Brian W. Kernighan, Dennis M.
Ritchie
Expert C Programming: Deep C Secrets by Peter Van, Der Linden
128
UNIT – 8 STRUCTURE AND UNIONS
Structure
8.0 Objectives
8.1 Introduction
8.2 Structure Variable Declaration
8.3 Accessing Members of Structure
8.4 Nested Structure
8.5 Structure and Functions
8.6 Union-Defining Structure
8.7 Array of structure
8.8 Structure assignment
8.9 Structures as Function Arguments
8.10 Pointers to structures
8.11 Typedefs
8.12 Unions
8.13 Bit fields
8.14 Summary
8.15 Key words
8.16 Questions for self-study
8.17 References
8.0 OBJECTIVES
8.1 INTRODUCTION
Structure is the collection of variables of different types under a single name for better
handling. For example: You want to store the information about person about his/her name,
citizenship number and salary. You can create this information separately but, better approach
129
will be collection of this information under single name because all these information are
related to person.
Structure Definition in C
Keyword struct is used for creating a structure.
Syntax of structure
struct structure_name
{
data_type member1;
data_type member2;
.
.
data_type memebern;
};
We can create the structure as mentioned in above example as:
struct person
{
char name[50];
int cit_no;
float salary;
};
This declaration above creates the derived data type struct person, i.e, a user-defined type.
When a structure is defined, it creates a user-defined type but, no storage is allocated. You can
use structure variable using tag name in any part of program. For example:
struct person
{
char name[50];
int cit_no;
float salary;
};
struct person p1, p2, p[20];
Another way of creating sturcture variable is:
struct person
{
130
char name[50];
int cit_no;
float salary;
}p1 ,p2 ,p[20];
In the above cases, 2 variables p1, p2 and array p having 20 elements of type struct
person are created.
There are two types of operators used for accessing members of a structure.
Member operator(.)
Structure pointer operator(->) (will be discussed in respective chapter of structure and
pointers)
Any member of a structure can be accessed as: structure_variable_name.member_name
Suppose, if we want to access salary for variable p2. Then, it can be accessed as: [Link]
Consider following Example of structure
#include <stdio.h>
struct Distance{
int feet;
float inch;
}d1,d2,sum;
int main(){
printf("1st distance\n");
printf("Enter feet: ");
scanf("%d",&[Link]); //input of feet structure for d1
printf("Enter inch: ");
scanf("%f",&[Link]); //input of inch structure for d1
printf("2nd distance\n");
printf("Enter feet: ");
scanf("%d",&[Link]); //input of feet for structure variable d2
printf("Enter inch: ");
scanf("%f",&[Link]); //input of inch for structure variable d2
[Link]=[Link]+[Link];
[Link]=[Link]+[Link];
if ([Link]>12){ //If inch is greater than 12, changing it to feet.
++[Link];
[Link]=[Link]-12;
}
printf("Sum of distances=%d\'-%.1f\"",[Link],[Link]); //printing
sum of distance d1 and d2
return 0;
}
131
Structure is the collection of variables of different types under a single name for better
handling. For example: You want to store the information about person about his/her name,
citizenship number and salary. You can create this information separately but, better approach
will be collection of these information under single name because all these information are
related to person.
Keyword typedef while using structure
Programmers are generally use typedef while using structure in C language. For example:
typedef struct complex{
int imag;
float real;
}comp;
comp c1,c2;
Here, typedef keyword is used in creating a type comp(which is same type as struct complex).
Then, two structure variables c1 and c2 are created by this comp type.
In the C programming language, a nested structure is a data structure that contains another
data structure within it. This means that a structure can be a member of another structure,
creating a hierarchy of related data. Before understanding nested structure, we have to
understand what is structure in c.
Structures within structures
In C, the structure is a user-defined data type that is used to store a group of items of different
data types as a single data type. Each element of a structure is known as its [Link]
can be nested within other structures in C programming.
struct complex
{
int imag_value;
float real_value;
};
struct number{
struct complex c1;
int real;
}n1,n2;
Suppose you want to access imag_value for n2 structure variable then, structure
132
member n1.c1.imag_value is used.
typedef struct complex complex; complex_no c1,c2,c3;
Here, typdef is used to create a type complex. This type complex is then used in declaring
variables c1, c2 and c3.
133
Name: Kevin Amla
Roll: 149
#include <stdio.h>
struct distance{
int feet;
float inch;
};
void Add(struct distance d1,struct distance d2, struct distance
*d3);
//function prototype
int main()
{
struct distance dist1, dist2, dist3;
printf("First distance\n");
printf("Enter feet: ");
scanf("%d",&[Link]);
printf("Enter inch: ");
scanf("%f",&[Link]);
printf("Second distance\n");
printf("Enter feet: ");
scanf("%d",&[Link]);
printf("Enter inch: ");
scanf("%f",&[Link]);
Add(dist1, dist2, &dist3);
Output
First distance
Enter feet: 12
Enter inch: 6.8
Second distance
Enter feet: 5
Enter inch: 7.5
Sum of distances = 18'-2.3"
In this program, structure variables dist1 and dist2 are passed by value (because value of dist1
and dist2 does not need to be displayed in main function) and dist3 is passed by reference, i.e,
address of dist3 (&dist3) is passed as an argument. Thus, the structure pointer variable d3
points to the address of dist3. If any change is made in d3 variable, effect of it is seed in dist3
variable in main function.
Structures can be passed as function arguments like all other data types. We can pass
individual members of a structure, an entire structure, or a pointer to a structure to a function.
Like all other data types, a structure or a structure member or a pointer to a structure can be
returned by a function. Structure-function helps in writing better code. Structure functions in
C make the code efficient. A code that consumes less memory and takes less time to execute
is good.
Before we jump into the concept of structure and functions in C. Let us go through some
prerequisites. Functions are reusable codes that perform a specific task when they are called.
Derived data types are formed from fundamental data types. Structures are one such user-
defined data type. The structures can have many fundamental data types known as structure
members grouped into a single user-defined data type. Functions are the blocks of codes that
perform a specific task when called. We need to pass the parameters to the function, and the
function returns the result. Structures can also be passed as parameters to the functions.
135
When a function is called, if we pass the values of the variables to the function, it is known as
the call by value. Instead of passing the values, if we pass the address of the variables to the
function, it is known as call by reference. The dot (.) operator is used to access a structure
member. The arrow (->) operator is to access the members of a structure when the pointer
references the structure. With these basics of structures and functions, It will be easy to
understand structure functions clearly.
Structure-function can be effectively used while writing code. Structures can be passed as
arguments to the functions. This can be done in three ways. They are,
o Passing the members of the structures as an argument.
o Passing the entire structure as an argument.
o Passing the address of the structure as arguments.
Unions are quite similar to the structures in C. Union is also a derived type as structure. Union
can be defined in same manner as structures just the keyword used in defining union
in union where keyword used in defining structure was struct.
union car{
char name[50];
int price;
};
Union variables can be created in similar manner as structure variable.
union car{
char name[50];
int price;
}c1, c2, *c3;
OR;
union car{
char name[50];
int price;
};
union car c1, c2, *c3;
In both cases union variables c1, c2 and union pointer variable c3 of type union car is
136
created.
Accessing members of an union
Again, the member of unions can be accessed in similar manner as that structure. Suppose, we
you want to access price for union variable c1 in above example, it can be accessed as
[Link]. If you want to access price for union pointer variable c3, it can be accessed
as (*c3).price or as c3->price.
Difference between union and structure
Though unions are similar to structure in so many ways, the difference between them is
crucial to understand. This can be demonstrated by an example.
#include <stdio.h>
union job { //defining a union
char name[32];
float salary;
int worker_no;
}u;
struct job1 {
char name[32];
float salary;
int worker_no;
}s;
int main(){
printf("size of union = %d",sizeof(u));
printf("\nsize of structure = %d", sizeof(s));
return 0;
}
Output
size of union = 32
size of structure = 40
There is difference of memory allocation between union and structure as suggested in above
example. The amount of memory required to store a structure variable is the sum of memory
size of all members.
137
But, the memory required to store a union variable is the memory of largest element of union.
#include <stdio.h>
union job {
char name[32];
float salary;
int worker_no;
}u;
int main(){
printf("Enter name:\n");
scanf("%s",&[Link]);
printf("Enter salary: \n");
scanf("%f",&[Link]);
printf("Displaying\nName :%s\n",[Link]);
printf("Salary: %.1f",[Link]);
return 0;
}
Output
Enter name
Hillary
Enter salary
1234.23
Displaying
Name: f%Bary
Salary: 1234.2
Note: You may get different garbage value of name.
When code in line no. 9 is executed, Hillary will be stored in [Link] and other members of
union will contain garbage value. When code all will executed, 1234.23 will be stored in
[Link] and other members will contain garbage value. Thus in output, salary is printed
accurately but, name displays some random string.
138
8.7 ARRAY OF STRUCTURE
The following assignment of a struct to another struct does what one might expect. It is not
necessary to use memcpy() to make a duplicate of a struct type. The memory is already given
and zeroed by just declaring a variable of that type regardless of member initialization. This
should not be confused with the requirement of memory management when dealing with a
pointer to a struct.
#include <stdio.h>
/* Define a variable p of type point, and initialize all its members inline! */
point p = {1,2};
/* Define a variable q of type point. Members are initialized with the defaults for their
derivative types such as 0. */
point q;
A structure can be passed as a function argument just like any other variable. This raises a few
practical issues. Where we wish to modify the value of members of the structure, we must
140
pass a pointer to that structure. This is just like passing a pointer to an int type argument
whose value we wish to [Link] we are only interested in one member of a structure, it is
probably simpler to just pass that member. This will make for a simpler function, which is
easier to re-use. Of course if we wish to change the value of that member, we should pass a
pointer to [Link] a structure is passed as an argument, each member of the structure is
copied. This can prove expensive where structures are large or functions are called frequently.
Passing and working with pointers to large structures may be more efficient in such cases.
#include <stdio.h>
void input (dob_st *);
int main ()
{
typedef struct
{
int year;
int month;
int day;
}
dob_st;
dob_st date;
dob_st *p;
p=&date;
input (*p);
printf("%02i.",p->day);
printf("%02i.",p->month);
printf("%i.",p->year);
return 0;
}
void upis (dob_st *p)
{
printf ("Date of birth:\nDay?\n");
scanf ("%i",&(p->day));
printf ("Month?\n");
scanf ("%i",&(p->month));
141
printf ("Year?\n");
scanf ("%i",&(p->year));
}
Pointers can be used to refer to a struct by its address. This is particularly useful for passing structs to
a function by reference. The pointer can be dereferenced just like any other pointer in C —
using the *operator. There is also a -> operator in C which dereferences the pointer to struct
(left operand) and then accesses the value of a member of the struct (right operand).
struct point {
int x;
int y;
} my_point;
8.11 TYPEDEFS
Typedef is a keyword. The more theoretical information about the typedef is given in last unit.
Readers are directed to refer theoretical aspects from last unit. In this section we will see
programmatic aspects using typedef.
typedef struct {
int account_number;
char *first_name;
char *last_name;
float balance;
} account;
Different users have differing preferences; proponents usually claim:
shorter to write
can simplify more complex type definitions
As an example, consider a type that defines a pointer to a function that accepts pointers to
142
struct types and returns a pointer to struct:
Without typedef:
struct point {
int x;
int y;
};
typedef struct point *(*point_compare_t) (struct point *a, struct point *b);
With typedef:
struct point {
int x;
int y;
};
typedef struct point point_t;
typedef point_t *(*point_compare_t) (point_t *a, point_t *b);
If neither typedef were used in defining a function that takes a pointer to a type of the above
function pointer, the following code would have to be used. Although valid, it becomes
increasingly hard to read quickly.
/* Define a function that returns a pointer to the biggest point, using a function to do the
comparison. */
struct point * biggest_point (size_t size, struct point *points, struct point *(*point_compare)
(struct point *a, struct point *b))
{
int i;
struct point *biggest = NULL;
Now with all of the typedefs being used you should see that the complexity of the function
143
signature is drastically reduced.
/* Using the struct point type from before and all of the typedefs */
/* Define a function that returns a pointer to the biggest point, using a function to do the
comparison. */
point_t * biggest_point(size_t size, point_t * points, point_compare_t point_compare )
{
int i;
point_t * biggest = NULL;
They pollute the main namespace (see below), however this is easily overcome with prefixing
a library name to the type name.
Harder to figure out the aliased type (having to scan/grep through code), though most IDEs
provide this lookup automatically.
Typedefs do not really "hide" anything in a struct or union — members are still accessible
([Link]) (To really hide struct members, one needs to use 'incompletely-declared'
structs.)
8.12 UNIONS
In computer science, a union is a value that may have any of several representations or
formats; or a data structure that consists of a variable which may hold such a value.
Some programming languages support special data types, called union types, to describe such
values and variables. In other words, a union type definition will specify which of a number of
permitted primitive types may be stored in its instances, e.g. "float or long integer". Contrast
with a record, which could be defined to contain a float and an integer; whereas, in a union,
144
there is only one value at a time.
Depending on the language and type, a union value may be used in some operations, such
as assignment and comparison for equality, without knowing its specific type. Other
operations may require that knowledge, either by some external information, or by the use of
a tagged union.
Because of the limitations of their use, untagged unions are generally only provided in
untyped languages or in an unsafe way (as in C). They have the advantage over simple tagged
unions of not requiring space to store the tag.
The name "union" stems from the type's formal definition. If one sees a type as the set of all
values that that type can take on, a union type is simply the mathematical union of its
constituting types, since it can take on any value any of its fields can. Also, because a
mathematical union discards duplicates, if more than one field of the union can take on a
single common value, it is impossible to tell from the value alone which field was last written.
However, one useful programming function of unions is to map smaller data elements to
larger ones for easier manipulation. A data structure, consisting for example of 4 bytes and a
32-bit integer, can form a union (in this case with an unsigned 64-bit integer) and thus be
more readily accessed for purposes of comparison [Link] a structure, all of the members of a
union are by default public. The keywords private, public, and protected may be used inside a
struct or a union in exactly the same way they are used inside a class for defining private,
public, and protected members.
A bit field is a common idiom used in computer programming to compactly store multiple
logical values as a short series of bits where each of the single bits can be addressed
separately. A bit field is most commonly used to represent integral types of known, fixed bit-
width. A well-known usage of bit-fields is to represent single bit flags with each flag stored in
a separate bit.
A bit field is distinguished from a bit array in that the latter is used to store a large set of bits
indexed by integers and is often wider than any integral type supported by the language. Bit
fields, on the other hand, typically fit within a machine word, and the denotation of bits is
independent of their numerical index.
8.14 SUMMARY
At the end this unit we have learnt the concepts about structure and unions. We have
145
introduced structure through basic thing such as declaring a structure, accessing structure
members. A suitable piece of code as an example taken and demonstrated how exactly the
structure concepts works. In later sections we have touch upon advanced concepts on structure
such as passing structure as a function argument and returning the value. In the last section of
this unit, we have introduced union defining function.
8.15 KEYWORDS
struct,
typedef,
passing by reference
146
UNIT 9: INPUT AND OUTPUT
Structure:
9.0 Objectives
9.1 Introduction
9.2 Input and output
9.0 OBJECTIVES
9.1 INTRODUCTION
Input and Output in C programming language are accomplished through library functions. C
programming language has defined many library functions for input and output. In C
programming, scanf () and printf () functions are most commonly used standard library function for
taking input form keyboard and printing output on screen respectively. Here, when we are say Input
that means feeding data into C program using the keyboard and
147
output means printing data on screen. We will discuss file Input and Output in separate section. Most of
the standard library function for Input and Output is defined in stdio.h header file.C programming
language treats all the I/O devices and files as stream of data. A C programreading data from
keyboard is similar to reading data from a file similarly printing data on screen is similar to writing
data on a file. Three streams gets automatically attached when a program starts execution.
Input refers to feeding data into the program, and Output refers to getting data out of the program.
Input and Output in C are done using the Standard Input/Output library, which we could include in the
program using stdio.h header file consists of Input and Output functions in C like scanf() for input and
printf() for output. Streams in C programming are used to take input or give output to put away worries
about the data's initial location or final destination.
Input is given through the keyboard, and output may be shown on screen or printed through the
printer or in another way. Still, for the different devices, there may be a different type of process for
input/output, which may be a problem for the programmer. To avoid this, all input/output are done
using streams in C, which handles input/output without taking care of where input is coming and the
destination of the output. It can be added to any C program by introducing a Standard Input/Output
library using stdio.h header.
Stream is the sequence of bytes of data in the form of a sequence of characters. While taking input, we
get a sequence of characters entering into our program, that is, the input stream and for output, we
send a sequence of characters out from our program, which is the output stream. The main advantage of
the stream is it makes input/output programming independent of the device.
Input means to provide the program with some data to be used in it.
Output means to display data on the screen or write the data to a printer or a file.
The C programming provides standard library functions to read any given input and display
output on the console.
While dealing with input-output operations in C, we use the following two streams:
148
Standard Input (stdin)
Standard Output (stdout)
Standard input or stdin is used for taking input.
Standard output or stdout is used for giving output.
The functions used for standard input and output are present in the stdio.h header file.
Hence, to use those functions, we need to include the stdio.h header file in our program, as
shown below.
#include<stdio.h>
Functions Used for Input and Output
C language offers us several built-in functions for performing input/output operations. The following
are the functions used for standard input and output:
In C Language, output devices like computer monitors, printers, etc. are treated as files and the same
process is followed to write output to these devices as would have been followed to write the output to
a file.
Copy
It writes the C string pointed by the format pointer to the standard output (stdout).
On success, the total number of characters written is returned.
149
This function is used to print a simple text sentence or value of any variable which can
be of int, char, float, or any other datatype.
1. Print a sentence
<stdio.h>
int main() {
// using printf()
0;
Copy
To understand the complete code and structure of a basic C language program, check Hello
World Program in C.
We can use the printf() function to print an integer value coming from a variable using the %d
format specifier.
For example,
#include <stdio.h>
150
int main() {
int x = 10;
// using printf()
printf("Value of x is: %d", x);
return 0;
}
Value of x is: 10
In the program, above we have used the %d format specifier, to specify the type of
value that will be added there.
The format specifiers %d and %i are used for integer values.
The %c format specifier is used to print character variable values using the printf() function.
In the code example below, we have used the printf() function to print values of a float
and double type variable.
For float value we use the %f format specifier and for double value we use the %lf format
specifier.
#include <stdio.h>
int main() {
// using printf() float
num1 = 15.50;
double num2 = 15556522.0978678
printf("Value of num1 is: %f \n", num1);
printf("Value of num2 is: %lf", num2); return
0;
}
Output:
Value of num is: 15.500000
151
Value of num2 is 15556522.097868
We have used the \n Escape sequence which is used for a newline at the end of the first
printf() statement so that the next printf() statement output is shown in the next line.
int main() {
// using printf() for multiple outputs int
day = 20;
int month = 11; int
year = 2021;
printf("The date is: %d-%d-%d", day, month, year);
return 0;
}
As you can see in the code example above, we can do the formatting and print values of
multiple variables using the printf() function.
We can also perform some simple calculations inside printf(). Here is a simple example of that,
#include <stdio.h>
int main()
{
int a = 5, b = 6; printf("%d", a + b);
return 0;
}
Output :11
152
Format Specifiers
To print values of different data types using the printf() statement and while taking
input using the scanf() function, it is mandatory to use format specifiers.
int %d, %i
char %c
float %f
double %lf
unsigned int %u
signed char %c
unsigned char %c
153
9.4 THE SCANF () FUNCTION
When we want to take input from the user, we use the scanf() function and store the input value
into a variable.
scanf("%x", &variable);
where, %x is the format specifier.
Using the format specifier, we tell the compiler what type of data to expect from the user.
The & is the address operator which tells the compiler the address of the variable so that the
compiler can store the user input value at that address.
If we have to take an integer value input from the user, we have to define an integer variable and then
use the scanf() function.
#include <stdio.h>
154
int main() {
// using scanf()
int user_input;
printf("Please enter a number: ");
scanf("%d", &user_input); printf("You
entered: %d", user_input); return 0;
}
You entered: 7
NOTE: If you use our compiler, then while running the code example above, there is a button for
Input at the top-right corner of the editor, you can click on it and provide custom value for input.
In the above code example, we have used %d format specifier to inform the
scanf() function that user input will be of type int.
And we have also used & symbol before the name of the variable, because
&user_input refers to the address of the user_input variable where the input value will
be stored.
Just like integer value, we can take input for any different datatype. Let's see an example of float
type value.
#include <stdio.h>
int main() {
// using scanf()
float user_input;
printf("Please enter a decimal number: "); scanf("%f",
&user_input);
printf("You entered: %f", user_input);
155
return 0;
}
Output:
We have used the %f format specifier and defined a float type variable.
Try doing the same for taking a double type value as user input.
The format specifier for double is %lf.
Your gender: M
156
int age;
printf("Enter your age and then gender(M, F or O): "); scanf("%d
%c", &age, &gender);
printf("You entered: %d and %c", age, gender);
return 0;
}
Output:
studytonightValue of i is: 12
The getchar and putchar functions are used for taking character input from the user and printing the
character as output.
The getchar() function reads a character from the terminal and returns it as an integer.
This function reads only a single character at a time.
157
int getchar(void);
You can use this method in a loop if you want to read more than one character. The
putchar() function
The putchar() function displays the character passed to it on the screen and returns the same
character.
This function too displays only a single character at a time.
Output:
158
When you will compile the above code, it will ask you to enter a value. When you will enter the value,
it will display the value you have entered.
The gets and puts functions are used for taking string input and giving string output. The gets()
function
The gets() function reads a line of text from stdin(standard input) into the buffer pointed to by str
pointer, until either a terminating newline or EOF (end of file) occurs.
Here is the syntax for the gets() function:
char* gets(char* str);
The puts() function
The puts() function writes the string str with a newline character ('\n') at the end to stdout. On success,
a non-negative value is returned.
Here is the syntax for the gets() function:
str is the pointer to an array of chars where the C string is stored (Don't worry if you are not able to
understand this now.)
#include <stdio.h>
void main()
{
/* character array of length 100 */ char
str[100];
printf("Enter a string: ");
gets(str);
puts(str);
getch();
return 0;
}
Output:
Studytonight
159
When you will compile the above code, it will ask you to enter a string.
When you will enter the string, it will display the value you have entered.
The gets() function is considered dangerous to use and should be avoided. We get a warning when we
compile any code in which we have used gets() function. This is because the function doesn't know how
big the buffer is, so it continues reading until it finds a newline or encounters EOF, and may overflow
the bounds of the buffer it was given. We can use alternatives to gets() function, like the fgets()
function.
#include <stdio.h>
#define MAX 10 int
main()
{
char str[MAX]; fgets(str,
MAX, stdin);
printf("The string is: %s", str);
return 0;
}
Output: abcdefghijkl
160
9.7 FILE HANDLING IN C
File handing in C is the process in which we create, open, read, write, and close operations on a file.
C language provides different functions such as fopen(), fwrite(), fread(), fseek(), fprintf(), etc. to
perform input, output, and many different C file operations in our program.
In order to understand why file handling is important, let us look at a few features of using files:
Reusability: The data stored in the file can be accessed, updated, and deleted anywhere
and anytime providing high reusability.
Portability: Without losing any data, files can be transferred to another in the computer
system. The risk of flawed coding is minimized with this feature.
Efficient: A large amount of input may be required for some programs. File handling
allows you to easily access a part of a file using few instructions which saves a lot of time
and reduces the chance of errors.
Storage Capacity: Files allow you to store a large amount of data without having to
worry about storing everything simultaneously in a program.
Types of Files in C
A file can be classified into two types based on the way the file stores the data. They are as follows:
Text Files
Binary Files
1. Text Files
A text file contains data in the form of ASCII characters and is generally used to store a
stream of characters.
Each line in a text file ends with a new line character (‘\n’).
It can be read or written by any text editor.
They are generally stored with .txt file extension.
161
Text files can also be used to store the source code.
2. Binary Files
A binary file contains data in binary form (i.e. 0’s and 1’s) instead of ASCII characters. They
contain data that is stored in a similar manner to how it is stored in the main memory.
The binary files can be created only from within a program and their contents
can only be read by a program.
More secure as they are not easily readable.
They are generally stored with .bin file extension.
C File Operations
C file operations refer to the different possible operations that we can perform on a file in C such as:
1. Creating a new file – fopen() with attributes as “a” or “a+” or “w” or “w+”
2. Opening an existing file – fopen()
3. Reading from file – fscanf() or fgets()
4. Writing to a file – fprintf() or fputs()
5. Moving to a specific location in a file – fseek(), rewind()
6. Closing a file – fclose()
The highlighted text mentions the C function used to perform the file operations.
162
File Pointer in C
A file pointer is a reference to a particular position in the opened file. It is used in file handling to
perform all file operations such as read, write, close, etc. We use the FILE macro to
declare the file pointer variable. The FILE macro is defined inside <stdio.h> header file.
FILE* pointer_name;
File Pointer is used in almost all the file operations in C.
Open a File in C
For opening a file in C, the fopen() function is used with the filename or file path along with the
required access modes.
Syntax of fopen()
163
FILE* fopen(const char *file_name, const char *access_mode);
Parameters
file_name: name of the file when present in the same directory as the source file.
Otherwise, full path.
access_mode: Specifies for what operation the file is being opened.
Return Value
File opening modes or access modes specify the allowed operations on the file to be opened. They
are passed as an argument to the fopen() function. Some of the commonly used file access modes are
listed below:
Opening
Modes Description
Searches file. If the file is opened successfully fopen( ) loads it into memory
r and sets up a pointer that points to the first character in it. If the file cannot be
opened fopen( ) returns NULL.
Open for reading in binary mode. If the file does not exist, fopen( ) returns
rb
NULL.
Open for reading in text mode. If the file exists, its contents are overwritten. If
w the file doesn’t exist, a new file is created. Returns NULL, if unable to open the
file.
Open for writing in binary mode. If the file exists, its contents are overwritten.
wb
If the file does not exist, it will be created.
a Searches file. If the file is opened successfully fopen( ) loads it into memory
164
Opening
Modes Description
and sets up a pointer that points to the last character in it. If the file doesn’t
exist, a new file is created. Returns NULL, if unable to open the file.
Open for append in binary mode. Data is added to the end of the file. If the file
ab
does not exist, it will be created.
Searches file. It is opened successfully fopen( ) loads it into memory and sets up
r+ a pointer that points to the first character in it. Returns NULL, if unable to open
the file.
Open for both reading and writing in binary mode. If the file does not exist,
rb+
fopen( ) returns NULL.
Searches file. If the file exists, its contents are overwritten. If the file doesn’t
w+
exist a new file is created. Returns NULL, if unable to open the file.
Open for both reading and writing in binary mode. If the file exists, its contents
wb+
are overwritten. If the file does not exist, it will be created.
Searches file. If the file is opened successfully fopen( ) loads it into memory and
a+ sets up a pointer that points to the last character in it. If the file doesn’t exist, a
new file is created. Returns NULL, if unable to open the file.
Open for both reading and appending in binary mode. If the file does not exist,
ab+
it will be created.
As given above, if you want to perform operations on a binary file, then you have to append ‘b’ at the
last. For example, instead of “w”, you have to use “wb”, instead of “a+” you have to use “a+b”.
165
Example of Opening a File
Output
The file is not opened. The program will now exit.
The file is not opened because it does not exist in the source directory. But the fopen() function is
also capable of creating a file if it does not exist. It is shown below
Create a File in C
The fopen() function can not only open a file but also can create a file if it does not exist already.
For that, we have to use the modes that allow the creation of a file if not found such as w,
w+, wb, wb+, a, a+, ab, and ab+.
FILE *fptr;
166
Example of Opening a File
// C Program to create a
file#include <stdio.h>
#include <stdlib.h>
int main()
{
// file
pointerFILE*
fptr;
exit(0);
}
else {
Output
The file is created Successfully.
167
Function Description
Function Description
fscanf() Use formatted string and variable arguments list to take input from a file.
So, it depends on you if you want to read the file line by line or character by character.
Example:
FILE * fptr;
c = fgetc(fptr);
The getc() and some other file reading functions return EOF (End Of File) when they reach the end of
the file while reading. EOF indicates the end of the file and its value is implementation- defined.
Note: One thing to note here is that after reading a particular part of the file, the file pointer will be
automatically moved to the end of the last read character.
Write to a File
The file write operations can be performed by the functions fprintf() and fputs() with similarities to
read operations. C programming also provides some other functions that can be used to write data to
a file such as:
168
Function Description
Function Description
Similar to printf(), this function use formatted string and varible arguments list
fprintf()
to print output to the file.
fputs() Prints the whole line in the file and a newline at the end.
fwrite() This functions write the specified amount of bytes to the binary file.
Example:
FILE *fptr ;
fptr);
Closing a File
The fclose() function is used to close the file. After successful file operations, you must always
close a file to remove it from the memory.
Syntax of fclose()
fclose(file_pointer);
fptr= fopen(“[Link]”, “w”);
fclose(fptr);
169
9.8 SUMMARY
In this unit we have studied in detail input and output functions. We also dealt with printf() and scanf()
function. We have discussed getchar() and putchar() functions and also gets() and puts() function. At the
end of this unit we have explained in detail about file handling in C.
9.9 KEYWORDS
Input,
Output,
printf(),
scanf(),
getchar() and putchar().
9.11 REFERENCES
170
UNIT 10: TYPEDEF AND ENUMERATION IN C
Structure:
10.0 Objectives
10.1 Introduction
10.2 Typedef in C
10.3 Enumeration in C
10.4 Summary
10.5 Keywords
10.6 Questions
10.7 References
10.0 OBJECTIVES
After studying this unit, we will be able to explain the following:
Typedef in C.
Enumeration in C.
10.1 INTRODUCTION
To make the coding of a program more intelligible, it is sometimes useful to replace integer values
such as 1, 2, 3 etc. with meaningful names. An enumeration is created withthe enum keyword, and
is an ordered collection of names that represent integer [Link] otherwise specified, the first
name in the collection represents 0, the second name represents 1, and so on. In the
statement below, for example, the names false and true become synonymous with the
integer values 0 and 1.
It is perfectly possible to define an enumerated data type using the typedef keyword. This keyword
allows you to give a new name to an existing data type - you can think of it as an alias
- with the aim of making the source code easier to follow. This might be useful, for example, if you
wanted to create a Boolean data type for your program. A variable of type Boolean can take one of
two values - false or true (represented by the values 0 and 1 respectively). While many programming
languages have a specific Boolean data type, C does not. We could therefore create a Boolean data
type with the following statement:
171
typedef enum {false, true} boolean;
We can now create a variable of this type (boolean) using a statement such as the following:
Supposing you want to be able to handle a situation in which the user enters a value that does not
match one of the expected responses. Your program should be able to "trap" such an error, and report
its occurrence to the user. The short program below expects the user to enter a temperature value, and
then respond to a question about whether or not it is raining by pressing either "Y" or "N" (for "yes"
or "no"). If the user responds to this question with
anything other than "Y" or "N", the variable input_error (of type boolean) is set to true (1), indicating
that an input error has occurred. The variable is initialised to false (0), so if a valid response is given,
10.2 TYPEDEF IN C
The typedef is a keyword used in C programming to provide some meaningful names to the already
existing variable in the C program. It behaves similarly as we define the alias for the commands. In
short, we can say that this keyword is used to redefine the name of an already existing variable.
Syntax of typedef
In the above syntax, 'existing_name' is the name of an already existing variable while 'alias name' is
another name given to the existing variable.
For example, suppose we want to create a variable of type unsigned int, then it becomes a tedious
task if we want to declare multiple variables of this type. To overcome the problem, we use a typedef
keyword.
In the above statements, we have declared the unit variable of type unsigned int by using a typedef
keyword.
Now, we can create the variables of type unsigned int by writing the following statement: unit a, b;
172
instead of writing: unsigned int a, b;
Till now, we have observed that the typedef keyword provides a nice shortcut by providing an
alternative name for an already existing variable. This keyword is useful when we are dealing with the
long data type especially, structure declarations.
#include <stdio.h>
int main()
{
typedef unsigned int unit;
unit i,j;
i=10;
j=20;
printf("Value of i is :%d",i);
printf("\nValue of j is :%d",j);
return 0;
}
Output
of j is :20
struct student
{
char name[20];
int age;
};
struct student s1;
In the above structure declaration, we have created the variable of student type by writing the
following statement:
173
1. struct student s1;
The above statement shows the creation of a variable, i.e., s1, but the statement is quite big. To avoid
such a big statement, we use the typedef keyword to create the variable of type student.
struct student
{
char name[20];
int age;
};
typedef struct student
stud;stud s1, s2;
In the above statement, we have declared the variable stud of type struct student. Now, we can use the
stud variable in a program to create the variables of type struct student.
From the above declarations, we conclude that typedef keyword reduces the length of the code and
complexity of data types. It also helps in understanding the program.
#include <stdio.h>
typedef struct student
{
char name[20];
int age;
}stud;
174
int main()
{
stud s1;
printf("Enter the details of student s1: ");
printf("\nEnter the name of the student:");
scanf("%s",&[Link]);
printf("\nEnter the age of student:");
scanf("%d",&[Link]);
printf("\n Name of the student is : %s", [Link]);
printf("\n Age of the student is : %d", [Link]); return
0;
}
Output
of the student is : 28
We can also provide another name or alias name to the pointer variables with the help of the typedef.
int* ptr;
In the above statement, we have declared the variable of type int*. Now, we can create the
175
variable of type int* by simply using the 'ptr' variable as shown in the below statement: ptr p1, p2
10.3 ENUMERATION IN C
Syntax :
e.g.
enum day { MON, TUE, WED, THU, FRI, SAT, SUN };
And, MON, TUE, WED, ......... are the values of type day.
By default, MON is 0, TUE is 1 and so on. This is done by compiler and it starts from 0, You can
change default values of enum elements during declaration (if necessary).
Example :
Output:
012345
176
Points to remember :
#include<stdio.h>
enum exam {Pass = 1, Failed = 0, Awaited = 0};
int main()
{
printf("%d, %d, %d", Pass, Failed, Awaited); return 0;
}
Output
1,0,0
If we do not explicitly assign values to enum names, the compiler by default assigns values starting
from 0. For example, in the following C program, MON gets value 0, TUEgets 1, and so on.
Output:
0123456
Output
177
We can assign values to some name in any order. All unassigned names get value as value
of previous name plus one.
Output
123789
All enum constants must be unique in their scope. For example, the following program fails in
compilation.
#include<stdio.h> enum e1 {a,
b};
enum e2 {a, b}; int main ( )
{
return 0;
}
Output
Compilation Error
Enumeration or Enum in C is a special kind of data type defined by the user. It consists of constant
integrals or integers that are given names by a user. The use of enum in C to name the integer values
makes the entire program easy to learn, understand, and maintain by the same or even different
programmer.
178
Syntax to Define Enum in C
An enum is defined by using the ‘enum’ keyword in C, and the use of a comma separates the
constants within. The basic syntax of defining an enum is:
179
Example 1: Printing the Values of Weekdays
#include <stdio.h>
enum days{Sunday=1, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday}; int
main(){
// printing the values of weekdays for(int
i=Sunday;i<=Saturday;i++){
printf("%d, ",i);
}
return 0;
}
Output:
1,2,3,4,5,6,7,
In the above code, we declared an enum named days consisting of the name of the weekdays starting
from Sunday. We then initialized the value of Sunday to be 1. This will assign the value for the other
days as the previous value plus 1. To iterate through the enum and print the values of each day, we have
created a for loop and initialized the value for i as Sunday.
180
cur_cont = cont1;
printf("Value of hearts is = %d \n", cur_cont);
return 0;
}
Output:
Value of cont2 is=7
Value of cont3 is =3
Value of hearts is =5
We have declared an enum named containers with four different containers as the elements in the
above code. We have then given custom values to the elements and initialized the variable for the
enum multiple times to print the relevant output.
181
case North:
printf("We are headed towards North.");
break;
case East:
printf("We are headed towards East."); break;
case West:
printf("We are headed towards West.");
break;
case South:
printf("We are headed towards South");
break;
}
return 0;
}
Output:
We are headed towards west
We can use enum in C for flags by keeping the values of integral constants a power of 2. This will
allow us to choose and combine two or more flags without overlapping with the help of the Bitwise
OR (|) operator. Let’s consider the example below where we set three flags: Crop, Rotate, and Save to
work with an image.
Example: #include
<stdio.h>
enum designFlags{
CROP = 1,
ROTATE = 2,
SAVE = 4
};
182
int main() {
int myExample = ROTATE | SAVE;
printf("%d", myExample);
return 0;
}
Output:
6
00000110 (Output = 6)
As you can see, our calculation and the output given by the program are the same. This
concludes that we can use enum in C for flags. Also, we can add our custom flags.
There are a few facts about the enum worth noting, such as:
1. Multiple enum names or elements can have the same value. Here’s an example of two
enum elements having a similar value.
Example:
#include <stdio.h>
enum Cars{Jeep = 1, BMW = 0, Mercedes_Benz = 0}; int
main(){
printf("%d, %d, %d", Jeep, BMW, Mercedes_Benz);
return 0;
}
Output:
1,0,0
183
2. If we do not assign custom values to enum elements, the compiler will assign them default
values starting from 0. For instance, the compiler will assign values to the months in the
example below, with January being 0.
Example:
#include <stdio.h>
enum Months{January, February, March, April, May, June, July, August, September, October,
November, December};
int main(){
enum Months m = May;
printf("The Value of May in Months is %d", m); return
0;
}
Output:
The value of May in Months is 4
3. We can provide values to any elements of enum in any order. All the unassigned elements
will get the value as previous + 1. The following program demonstrates the same.
Example:
#include <stdio.h>
enum weekdays {Sunday, Monday = 2, Tuesday, Wednesday = 6, Thursday, Friday = 9,
Saturday = 12};
int main()
{
printf("%d %d %d %d %d %d %d", Sunday, Monday, Tuesday, Wednesday,
Thursday, Friday, Saturday);
return 0;
}
Output:
0,2,3,6,7,9,1
184
4. All the values assigned to the elements of enum must be an integral constant. For instance,
they should be within the range of minimum and maximum possible integers.
5. All the enum elements or constants should have a unique scope. It means that an element
cannot be a part of two different enums in the same program as it will fail during compilation.
Here’s an example:
Example:
#include <stdio.h>
enum Cars{Mahindra, Jeep, BMW};
enum Luxury_Cars{BMW, Ferrari, Mercedes_Benz}; int
main(){
return 0;
}
Output:
10.5 SUMMARY
In this unit we have studied in detail about typedef function in C and also explained typedef using with
pointers and structure. At the end of this unit we also explained enum or enumeration in detail.
185
10.6 KEYWORDS
Typedef
Enum,
10.8 REFERENCES
186
UNIT 11: BITWISE OPERATORS
Structure:
11.0 Objectives
11.1 Introduction
11.2 Bitwise operation
11.3 Bitwise operators
11.4 Summary
11.5 Keywords
11.6 Questions for self-study
11.7 References
11.0 OBJECTIVES
Bitwise operation.
Bitwise operators.
11.1 INTRODUCTION
The Bitwise Operator in C is a type of operator that operates on bit arrays, bit strings, and
tweaking binary values with individual bits at the bit level. For handling electronics and IoT-related
operations, programmers use bitwise operators. It can operate faster at a bit level.
The Bitwise Operator in C performs its operation on the individual bits of its operand, where
operands are values or expressions on which an operator operates. These operators are also used to
perform the core actions as well as high-level arithmetic operations that require direct support of the
processor. We can further subcategorize bitwise operators into three subtypes based on their working
principles, logical (Bitwise AND, OR, and XOR), Shift (Right Shift and left shift), and Complement
(Bitwise NOT).
Using bitwise operators, programmers can change the individual bits of any value contained in the
operand. We can view a single byte of computer memory as 8 -bits that signifies the true or false status
of 8 flags. Bitwise operators are usually applied to define flag values in operating systems and driver
software. For instance, in a file property, the read-only mode is conceptually expressed as a flag bit in
the operating system, and the bitwise operator is used to toggle between the true and the false value.
The Bitwise AND (&) in C: The C compiler recognizes the Bitwise AND with & operator. It takes
two operands and performs the AND operation for every bit of the two operand numbers. It is a binary
operator. The output of this operator will result in 1 only if both bits are 1.
The Bitwise OR (|) in C: The C compiler recognizes the Bitwise OR with | operator. It takes two
operands and performs the OR operation for every bit of the two operand numbers. It is also a binary
operator. The output of this operator will result in 1 if any oneof the two bits is 1.
The Bitwise XOR (^) in C: The C compiler recognizes the Bitwise XOR with ^ operator. It takes
two operands and performs the XOR operation for every bit of the two operand numbers. It is also a
binary operator. The output of this operator will result in 1 if both the bits have different values.
Binary One’s Complement or Bitwise NOT operator (~) in C: The C compiler recognizes the
Bitwise NOT with ~ operator. It takes only one operand and performs the inversion of all digits of it.
It is a unary operator. The output of this operator will invert all the existing bits of that operand.
Bitwise Left shift operator (<<) in C: The C compiler recognizes the left shift operation with this
<<. It takes only two operands and shifts all the bits of the first operand to the left. The second
operand decides how many numbers of places this operator will shift its bits. It is a binary operator.
Bitwise Right shift operator (>>) in C: The C compiler recognizes the left shift operation
with this >>. It takes only two operands and shifts all the bits of the first operand to the
188
right. The second operand decides how many numbers of places this operator will shift its bits. It is a
binary operator.
Bitwise is a level of operation that involves working with individual bits which are the smallest units of
data in a computing system. Each bit has single binary value of 0 or 1. Most programming languages
manipulate groups of 8, 16 or 32 bits. These bit multiples are known as bytes. The arithmetic logic
unit (ALU) is a part of a computer's CPU. Inside the ALU, mathematical operations like addition,
subtraction, multiplication and division are all done at bit level. For those operations, bitwise
operators are used.
Bitwise operations
A bitwise operation operates on two-bit patterns of equal lengths by positionally matching their
individual bits. For example, a logical AND (&) of each bit pair results in a 1 if both the first AND
second bits are 1. If only one bit is a 1, the result is 0. AND can also be used to test individual bits in a
bit string to see if they are 0 or 1.
A logical OR (|) operation functions differently from the AND operations. For each bit pair, the result
is 1 if the first OR second bit is 1. If neither bit is 1, the result is 0.
A logical XOR (~) of each bit pair results in a 1 if the two bits are different, and 0 if they are the same
(both zeros or both ones).
Logical NOT is represented as ^.
Left shift (<<), right shift (>>) and zero-fill right shift (>>>) bitwise operators are also known as bit
shift operators.
Arithmetic logic unit, part of a computer CPU, is where bitwise operators used to perform
mathematical operations.
189
11.3 BITWISE OPERATORS
Bitwise operators are characters that represent actions (bitwise operations) to be performed on single
bits. They operate at the binary level and perform operations on bit patterns that involve the
manipulation of individual bits. Thus, unlike common logical operators like + or - which work with
bytes or groups of bytes, bitwise operators can check each individual bit within a byte. The most
common bitwise operators used in C/C++ are given in the table below.
& Bitwise AND Copies a bit to the result if it To set up a mask to check
exists in both operands. The the values of specific bits
result is 1 only if both bits are
1.
190
Multiple bitwise operators are used in bit manipulation. These operations happen very fast and
optimize system performance and time complexity. It’s important to keep in mind that the left shift
and right shift operators should not be used for negative numbers. Doing this can result in undefined
behaviors in the programming language. Also, bitwise operators should not be used in place of logical
operators because they work differently. Logical operators consider non-zero operands as 1 and their
result is either 0 or 1. In contrast, bitwise operators return an integer value. The table below defines
the JavaScript bitwise operators.
191
Operator Name Type Action
low-level programming for device drivers, memory allocators and compression software;
maintaining large integer sets for search and optimization;
ability to store multiple Boolean flags on limited memory devices;
embedded software in chips and microcontrollers;
communications where individual header bits carry sensitive or important information;
and
192
converting text cases, such as uppercase to lowercase or lowercase to uppercase.
193
Bitwise AND
The bitwise AND operator produces an output of 1 if the corresponding bits of both the
operands are 1. If not, the output is 0.
Example 1: Bitwise AND operation of two one-bit operands.
0 0 0
0 1 0
1 0 0
1 1 1
Example 2: Bitwise AND operation of two integers: 28 and 17; the & operator compares
each binary digit of these integers.
Binary digits
28 0 0 0 1 1 1 0 0
17 0 0 0 1 0 0 0 1
Bitwise AND 0 0 0 1 0 0 0 0
output
Bitwise OR
The bitwise OR operator produces an output of 1 if either one of the corresponding bits is 1.
Otherwise, the output is zero.
194
Example 1: The bitwise OR operation of two one-bit operands.
0 0 0
0 1 1
1 0 1
1 1 1
Example 2: Let's consider the previous example of two integers: 28 and 17.
Binary digits
28 0 0 0 1 1 1 0 0
17 0 0 0 1 0 0 0 1
Bitwise OR output 0 0 0 1 1 1 0 1
The bitwise exclusive OR (XOR) operator returns 1 if the bits of both operands are opposite.
Otherwise, it returns 0.
195
Example 1: The bitwise XOR operation of two one-bit operands.
0 0 0
0 1 1
1 0 1
1 1 0
Example 2: Let's see how bitwise XOR works for our two integers 28 and 17.
Binary digits
28 0 0 0 1 1 1 0 0
17 0 0 0 1 0 0 0 1
Bitwise NOT
The bitwise NOT operator reverses the bits. Unlike other bitwise operators, it accepts only one
operand.
Example: Let's consider the bitwise NOT operation of the integer 28.
196
Binary digits
28 0 0 0 1 1 1 0 0
The bitwise left shift operator shifts the bits left by the bits specified by the right operand. The
positions vacated by the left shift operator are filled with 0.
Example: Let's perform the bitwise left shift operation on the integer 6. Each bit will be shifted
left by 1.
6 = 0110
Like the left shift operator, the bitwise right shift operator shifts the bits right by the bits specified by
the right operand. The positions vacated by the right shift operator are filled with 0.
Example: Let's perform the right shift by two bits operations on the integer 8. Each bit will be
shifted right by 2.
8 = 1000
197
11.4 SUMMARY
In this unit we have discussed about bitwise operations. We also discussed about bitwise operators
such as bitwise AND, bitwise OR, bitwise XOR, bitwise NOT, bitwise left shift and bitwise right shift.
11.5 KEYWORDS
Bitwise operator,
bitwise XOR,
bitwise AND,
bitwise OR,
11.7 REFERENCES
198
UNIT 12: DYNAMIC MEMORY ALLOCATION
Structure:
12.0 Objectives
12.1 Introduction
12.2 Dynamic memory allocation
12.3 Malloc() method
12.3 Calloc() method
12.4 Free() method
12.5 Realloc() method
12.6 Summary
12.7 Keywords
12.8 Questions
12.9 References
12.0 OBJECTIVES
12.1 INTRODUCTION
Dynamic Memory Allocation is unique feature of C Programming Language. This allows us to create
data types and structures of any size and length which suits our program. There are two common
application of dynamic memory allocation, these are while using dynamic
199
arrays and dynamic data structure e.g. linked lists in C Programs. Let’s see use case. There comes
a situation in programming, when we don’t know exact size of array until compiler compiles the code
and generate executable. The size of array we have declared maybe not enough or more than required.
In this case use of dynamic memory allocation is best solution. Now the question is how to allocate
dynamic memory? The answer is C Language supports 4 library functions which are knows as
memory management functions (malloc, calloc, realloc, f r e e ). These
functions are defined in #include<stdlib.h> header file. We will see each function
in detail. Let’s first understand organization of application memory. The heap is a part of application
memory which will be used while allocating and de-allocating memory using memory management
functions. The Heap is also known as Free Memory. The figure below will illustrate.
Now, Let us see the definition, syntax and some examples of each library functions below.
200
12.2 DYNAMIC MEMORY ALLOCATION
When we declare a variable or an array of any data type the space occupied by them in the
system's memory remains constant throughout the execution of the program. Sometimes the
constant space allocated at the compile-time may fall short, and to increase the space during
run-time we came through the concept of Dynamic Memory Allocation in C. Allocation and
Deallocation of memory at run-time in C are done using the concept of Dynamic Memory
Allocation. It is a method in which we use different library functionslike
malloc(), calloc(), realloc(), and free() to allocate and deallocate a memory block during run-
[Link] is considered as a very important topic because almost every Data Structure (such
asLinked Lists, Stack, Queue, Trees, etc.) is associated with the concept of Dynamic Memory
Allocation in [Link] understand Dynamic Memory Allocation in C, we first have to learn about
the types of memory that are used during the execution of a C Program
. There are two types of memory in our machine, one is Static Memory and another oneis
Dynamic Memory; both the memory are managed by our Operating System. Our operating
system helps us in the allocation and deallocation of memory blocks either during compile-
time or during the run-time of our program. When the memory is
allocated during compile-time it is stored in the Static Memory and it is known as Static
Memory Allocation, and when the memory is allocated during run-time it is stored in the
Dynamic Memory and it is known as Dynamic Memory [Link], let us see some
differences in Static Memory Allocation and Dynamic Memory Allocation.
It is used at compile-time of our program and is also It is used at run-time of our program and is also
known as compile-time memory allocation. known as run-time memory allocation.
We can't allocate or deallocate a memory block during We can allocate and deallocate a memory block during
run-time. run-time.
Heap space is used in Dynamic
Stack space is used in Static Memory Allocation.
Memory Allocation.
It doesn't provide reusability of memory, while the It provides reusability of memory, while the program i
program is running. So, it is less efficient.
201
How Does Memory Management in C works?
When we execute a C Program, it requires to reserve some memory in the machine to store its
variables, functions, instructions and the program file itself. However, we also have a memory segment
that we can use dynamically as much memory as the system have and that too during the run-time of a
program. So, now let us see the components/segments of memory that are used during the execution
of a C [Link] are further four components in which our system's memory is divided:
The amount of memory allocated for Stack, Global Variables, and Instructions / Text during compile-
time is invariable and cannot be reused until the program execution finishes. However, the Heap
segment of the memory can be used at run-time and can be expanded until the system's memory
exhausts.
Let's look at the some important points related to all the memory segments :
Instructions / Text
Global Variables
Global variable also known as static variables and can be declared by two methods,
o Using static keyword, ex. static int i = 0;
o Declaring variable outside main() or any other function.
These variables are stored in the Static Memory during the compile-time of our program.
Stack
Stack is a constant space (memory) allocated by our operating system to store local variables,
function calls and local statements that are present in the function definition. It is the major
part of the Static Memory in our system.
There are some drawbacks of stack space as follows:
o The memory allocated for stack can't grow during the run-time of an
202
application.
o We can't allocate or deallocate memory during execution.
Heap
Heap is the Dynamic Memory of our program, It can be also be imagined as a big free pool of
memory available to us. The space occupied by heap section is not fixed, it can vary during the
run-time of our program and there are functions to perform allocation and deallocation of
memory blocks during run-time.
Heap space can grow as long as we do not run out of the system's memory itself, however it is
not in the best interest of a programmer to exhaust the system's memory, so we need to be
really careful while using the heap space in our program.
Note : A machine's memory is one of the most useful resource available to us that can be used as both
Statically and Dynamically. So, we have to make sure to manage it well and not waste it during the
execution of our program.
Let us now see how our Operating System processes the allocation of memory through an example.
We will see how the memory is allocated at compile-time in this section using the example of
calculating Greatest Common Divisor (GCD) and Least Common Multiple (LCM).
C Program :
#include <stdio.h>
int sum; // global variable
// Declaring gcd and lcm functions, both takes two integer arguments,
// (memory will not be allocated upon declaring or defining our functions).
int greatestCommonDivisor(int, int); int
leastCommonMultiple(int, int);
// Defining greated common divisor function (also know as HCF).
int greatestCommonDivisor(int a, int b) { while (a
&& b) {
if (a > b) {
a %= b;
} else {
b %= a;
}
203
}
return a + b;
}
// Defining least common multiple function by using greatest common divisor.
int leastCommonMultiple(int a, int b) {
return (a / greatestCommonDivisor(a, b)) * b;
}
int main() {
int x, y;
printf("Enter two values to find their Greatest Common Divisor and Least Common
Multiple : ");
scanf("%d%d", &x, &y);
printf("Greatest Common Divisor : %d \nLeast Common Multiple : %d", greatestCommonDivisor(x, y),
leastCommonMultiple(x, y));
sum = greatestCommonDivisor(x, y) + leastCommonMultiple(x, y); printf("\nSum
of GCD and LCM : %d\n", sum);
return 0;
}
Output :
Enter two values to find their Greatest Common Divisor and Least Common Multiple : 12 15 Greatest
Common Divisor : 3
Least Common Multiple : 60
Sum of GCD and LCM : 63
The first rectangular box represents the memory reserved for text / instructions, second box as
memory reserved for global variables section, third box as the space reserved for stack and
fourth box represents the heap space.
When we run our program, first the main() function is called, then some amount of memory
from the stack frame is allocated for the execution of main() function and as sum is a
global variable, it has been given a space in the global segment.
204
Heap space remains empty throughout the execution of the program as there is no allocation
of memory during run-time.
The amount of memory allocated for a function in the stack can be called as a stack frame. All
of the local variables, arguments and the information in a function is stored within the stack
frame allocated to that function and as soon as a function returns something or reaches its last
statement, it is cleared from the stack memory.
When the main() finishes, program also finishes. In the end, space occupied by our global
variables also gets cleared.
malloc() is a method in C which is used to allocate a memory block in the heap section of the memory
of some specified size (in bytes) during the run-time of a C program. It is a library function present in
the <stdlib.h> header file.
Syntax of malloc()
General Syntax:
(cast-data-type *)malloc(size-in-bytes);
malloc() function takes size in bytes as an argument and returns a void pointer, so we have to type cast
the malloc() function to the required data type. malloc() does not initialises the allocated memory
block, so initially it contains a garbage value.
205
Defined in header <stdlib.h> as : void* malloc( size_t size );
o size : number of bytes to be allocated
Example Syntax:
In the above statement, we have assigned and allocated a block of size 4-bytes (64-bit compiler) with
cast data type as integer to an integer pointer ptr during the run-time of our program.
We can simply pass number of bytes instead of using sizeof() in argument, both are correct, but
sizeof() automatically takes care of the type of compiler and operating system that can cause changes
in sizes of different data types on different compilers and operating systems, so it is recommended to
use sizeof() function in Dynamic Memory Allocation in C.
Example of malloc()
Let's see an example to allocate a memory block of size 1-byte to a char pointer ptr during run- time
using malloc().
C Program :
int main() {
// Dynamically allocated variable, sizeof(char) = 1 byte.
char *ptr = (char *)malloc(sizeof(char));
if (ptr == NULL) {
printf("Memory Error!\n");
} else {
*ptr = 'S';
printf("%c", *ptr);
}
return 0;
}
Output :
206
S
Explanation :
In the main() function, first we have declared and initialized a char pointer ptr with a dynamic
memory block allocated using malloc() function.
(char *)malloc(sizeof(char)) returns address of a char block of size 1-byte.
char ptr contains the address of the memory block returned by the malloc() function.
Now, if the system memory is exhausted it will print Memory Error! (ptr = NULL) in the
output console, else we have assigned character S in the memory block pointed by ptr and
printf("%c", *ptr); prints S in the output.
return 0; exits the program successfully.
calloc() is a method in C which is also used to allocate memory blocks in the heap section, but it is
generally used to allocate a sequence of memory blocks (contiguous memory) like an array of
elements. It is also present in <stdlib.h> header file.
Syntax of calloc()
General Syntax:
calloc() function takes two arguments, first is the size of the array (number of elements) and second is
the sizeof() data type (in bytes) of which we have to make an array.
207
In the above statement, we are allocating an integer array of size 5 at run-time and assigning it to an
integer pointer arr, arr will store the address of the very first element of the allocated array.
Example of calloc()
We will see an example to allocate an character array of size n using calloc() method.
C Program :
int main() {
int n; scanf("%d",
&n);
// Dynamically allocated array of size 10 using calloc()
// array elements are initialized with 0
// arr stores the base address of the memory block
char *str = (char *)calloc(n, sizeof(char)); if
(str == NULL) {
printf("Memory Error!\n");
} else {
// initializing array with char variables
for (int i = 0; i < n; i++) {
char ch; scanf("%c",
&ch);
*(str + i) = ch;
}
// printing array using pointer
for (int i = 0; i < n; i++) {
printf("%c", *(str + i));
}
}
208
return 0;
}
Input:
14
Scaler Topics
Output:
Scaler Topics
Explanation :
In the main() function, first we have declared a integer variable n as it is the size of the
array or string that we are going to store in our dynamic memory.
We have declared and initialized a char pointer ptr with the dynamic array memory
allocated using calloc() function.
(char *)calloc(n, sizeof(char)) returns address of first element in the char array. str
contains the address of the first element of the array.
Now, if the system memory is exhausted it will print Memory Error! (str = NULL) in the
output console, else we have assigned a string Scaler Topics in our exampleoutput. printf("%c",
*str); statement inside the for loop will print each character of the Scaler
Topics string in the output.
return 0; exits the program successfully.
free() as the name suggests is used to free or deallocate a memory block previously allocated using
malloc() and calloc() functions during run-time of our program.
Syntax of free()
General syntax:
209
free( pointer );
free() takes one argument and it is the pointer containing the address of the memory block that is to
be freed or deallocated.
Example :
free(arr);
In the above statement, we are deallocating memory block(s) pointed by a pointer arr in the memory.
Let's extend our malloc() example and add free() method in it.
C Program :
int main() {
// dynamically allocated variable, sizeof(char) = 1 byte
char *ptr = (char *)malloc(sizeof(char));
if (ptr == NULL) {
printf("Memory Error!\n");
} else {
*ptr = 'S';
printf("%c", *ptr);
}
210
free(ptr); printf("\n%c
", *ptr);
// assign NULL to avoid garbage values
ptr = NULL; return
0;
}
Output :
S
garbage value
Explanation :
We have allocated a char block of size 1-byte using malloc() method and assigned it to a
character pointer ptr.
We are using the free() method to deallocate the memory block pointed by the pointer ptr in
the above example.
After deallocation of memory, ptr acts as a Dangling Pointer and is not pointing to any
location. It now contains some garbage value.
Assign NULL to the pointer ptr after using free() method to avoid garbage values in our
program.
In this example, let's also use our previous example of calloc() and add free() in it.
C Program :
#include <stdio.h>
#include <stdlib.h>
int main() {
int n; scanf("%d",
&n);
211
// array elements are initialized with 0
// arr stores the base address of the memory block
char *str = (char *)calloc(n, sizeof(char));
if (str == NULL) {
printf("Memory Error!\n");
} else {
// initializing array with Scaler Topics string
for (int i = 0; i < n; i++) {
char ch; scanf("%c",
&ch);
*(str + i) = ch;
}
return 0;
}
Input:
14
Scaler Topics
Output:
Scaler Topics
garbage value
212
Explanation :
We have allocated an array of size n using calloc() method and assigned it to a character
pointer str.
We are using the free() method to deallocates the whole array memory pointed by the pointer
str in the above example.
After deallocation of memory, str acts as a Dangling Pointer and is not pointing to any
location. It now contains some garbage value.
Assign NULL to the pointer str after using free() method to avoid garbage values in our
program.
When we allocate a memory block using malloc() or calloc(), the address of the memory block is
stored in a pointer that points to the allocated memory. We can easily deallocate
a memory block allocated by malloc() or calloc() method just by passing the pointer containing the
address of the block that is to be deallocated in to the free() method as an argument.
Free(ptr);
We have seen in the above examples of malloc() and calloc() to use free() function to deallocate
memory block(s). Let's see how free() works through a diagram. This is an example of deallocation of
integer memory block using free() function, previously allocated using malloc() [Link], let us
see how we can deallocate a memory block without using free() function.
We can deallocate a memory block without using free() function, alternatively using the
realloc() function, which is used in reallocation of memory blocks.
We will see more about this in the realloc() section and an example where we deallocate a memory
block using realloc().
213
12.6 REALLOC() METHOD
realloc() is also a method in C that is generally used to reallocate a memory block, here re- allocate
means to increase or decrease the size of a memory block previously allocatedusing malloc() or
calloc() methods. It can also be used to completely allocate or deallocate a memory block on its own,
we will see how to do it in the examples below.
Syntax of realloc()
realloc() takes two arguments, one is the pointer pointing the the memory which is to be
realloacted and second is the new size in bytes.
In the above statement, we are reallocating arr pointer's memory to reduce it to half and
assigning it to arr2 pointer, other half of the array will now contain garbage values.
realloc() function need to be type casted because the address returned by the realloc() does
not represent any data type.
realloc() function may change the address of the previously allocated block, so it is
recommended to store the new address in pointer or use some new pointer to store the
reallocated address.
Examples of realloc()
Program :
214
// C Program to reallocate memory blocks during run-time
#include <stdio.h>
#include <stdlib.h>
int main() {
int n; scanf("%d",
&n);
215
}
printf("\n");
return 0;
}
Input
5
0 1 650005713 46458 12462928
Output :
Explanation :
216
#include <stdio.h>
#include <stdlib.h>
int main() {
int *ptr = NULL;
ptr = (int *)realloc(ptr, sizeof(int));
if (ptr == NULL) {
printf("Memory Error!\n");
} else {
*ptr = 7;
printf("%d\n", *ptr);
printf("%d\n", *ptr);
return 0;
}
Output:
715078952
Memory
freed using
realloc()!
(output
garbage
values are
compiler
dependent)
217
Explanation :
malloc() vs calloc()
As we know, malloc() and calloc() both are library functions that are used to allocate memory block(s)
during the run-time of a program. But, there are some differences in malloc() and calloc()
methods and we are going see them below.
malloc() method calloc() method
It is generally used to allocate a single memory It is generally used to allocate contiguous
block of the given size (in bytes) during the run- (multiple) blocks of memory of given size (in
time of a program. bytes) during the run-time of a program.
It doesn't initializes the allocated memory block It initializes all the allocated memory blocks
and contains some garbage value. with 0 (zero) value.
calloc() takes two arguments i.e. the number of
malloc() takes a single arugment i.e. the size of
elements and the size of one element that are to be
memory block that is to be allocated.
allocated.
syntax: (cast-data-type *)calloc(num, size-in-
syntax: (cast-data-type *)malloc(size-in-bytes)
bytes)
Example : float *ptr = (float Example : float *ptr = (float *)calloc(10,
*)malloc(sizeof(float)); sizeof(float));
218
Note : malloc(n * sizeof(int)); and calloc(n, sizeof(int)); both allocates the same amount of memory,
but malloc() function does't initialize the elements in the memory(garbage values), while the calloc()
function initializes all the element in the memory to 0.
12.7 SUMMARY
In this unit we have studied dynamic memory allocation in detail. We also learnt malloc() method and
calloc() method. At the end of this unit explained free() method and realloc() method.
12.8 KEYWORDS
12.9 QUESTIONS
12.10 REFERENCES
219
UNIT 13
LINKED LISTS
Structure:
13.0 Objectives
13.1 Introduction
13.2 Singly Linked list
13.3 Circular linked List
13.4 Doubly linked list
13.5 Summary
13.6 Keywords
13.7 Questions for self study
13.8 References
13.0 OBJECTIVES
13.1 INTRODUCITON
A linked list is a linear data structure, in which the elements are not stored at contiguous memory
locations. The elements in a linked list are linked using pointers. In simple words, a linked list
consists of nodes where each node contains a data field and a reference (link) to the next node in
the list. Types of linked list are singly linked list, doubly linked list, priority linked list, circular
linked list. In general, the elements of linked list need not be in contiguous memory locations;
hence there will a pointer field in every node storing the address of next adjacent element
which will be
220
stored elsewhere in memory. So the logically adjacent elements need not be physically adjacent
in linked list. Here insertion, deletion are very easy.
13.2 SINGLY LINKED LIST
A linked list is a non-sequential collection of data items. It is a dynamic data [Link]
every data item in a linked list, there is an associated pointer that would give the memory location
of the next data item in the linked list.
The data items in the linked list are not in consecutive memory locations. They may be anywhere,
but the accessing of these data items is easier as each data item contains the addressof the next
data item.
Advantages of linked lists:
Linked lists have many advantages. Some of the very important advantages are:
1. Linked lists are dynamic data structures. i.e., they can grow or shrink during the execution
of a program.
2. Linked lists have efficient memory utilization. Here, memory is not preallocated. Memory is
allocated whenever it is required and it is de-allocated (removed) when it is no longer needed.
3. Insertion and Deletions are easier and efficient. Linked lists provide flexibility in inserting a
data item at a specified position and deletion of the data item from the given position.
4. Many complex applications can be easily carried out with linked lists.
Disadvantages of linked lists:
1. It consumes more space because every node requires a additional pointer to store address of
the next node.
2. Searching a particular element in list is difficult and also time consuming.
221
1. Linked lists are used to represent and manipulate polynomial. Polynomials are expression
containing terms with non zero coefficient and exponents. For example:
P(x) = a0 Xn + a1 X n-1 + a n-1 X + an
2. Represent very large numbers and operations of the large number such as addition,
multiplication and division.
3. Linked lists are to implement stack, queue, trees and graphs.
4. Implement the symbol table in compiler construction
222
Each node is allocated in the heap using malloc(), so the node memory continues to exist until it
is explicitly de-allocated using free(). The front of the list is a pointer to the “start” node. The link
field of the last node will store NULL value.
The beginning of the linked list is stored in a "start" pointer which points to the first node. The first
node contains a pointer to the second node. The second node contains a pointer to the third node,
... and so on. The last node in the list has its next field set to NULL to mark the end of the list.
Code can access any node in the list by starting at the start and following the next pointers.
The start pointer is an ordinary local pointer variable, so it is drawn separately on the left top to
show that it is in the stack. The list nodes are drawn on the right to show that they are allocated
in the heap.
Implementation of Single Linked List:
Before writing the code to build the above list, we need to create a start node, used to create and
access other nodes in the linked list. The following structure definition will do (see figure):
223
Creating a structure with one data item and a next pointer, which will be pointing to next node of
the list. This is called as self-referential structure. Initialise the start pointer to be NULL.
224
The following steps are to be followed to create ‘n’ number of nodes:
225
INSERTION OPERATION TO SINGLY LINKED LIST:
We can insert a new element to already created singly linked list by three ways
1. Inserting an element at the beginning of the list
2. Inserting an element at the end of the list
3. Inserting an element any where in the middle of the list
Inserting an element at the beginning of the list:
The following steps are to be followed to insert a new node at the beginning of the list:
Get the new node using getnode().
newnode = getnode();
If the list is empty then start = newnode.
If the list is not empty, follow the steps given below:
newnode -> next = start;
start = newnode;
226
else
{
newnode -> next = start;
start = newnode;
}
}
227
if(start == NULL)
{
start = newnode;
}
else
{
temp = start;
while(temp -> next != NULL)
temp = temp -> next;
temp -> next = newnode;
}
}
The following steps are followed, to insert a new node in an intermediate position in the
list:
Get the new node using getnode().
newnode = getnode();
Ensure that the specified position is in between first node and last node.
If not, specified position is invalid. This is done by countnode() function.
Store the starting address (which is in start pointer) in temp and prev pointers. Then
traverse the temp pointer upto the specified position followed by prev pointer.
After reaching the specified position, follow the steps given below:
prev -> next = newnode;
228
newnode -> next = temp;
The function insert_at_mid(), is used for inserting a node in the intermediate position.
void insert_at_mid()
{
node *newnode, *temp, *prev;
int pos, nodectr, ctr = 1;
newnode = getnode();
printf("\n Enter the position: ");
scanf("%d", &pos);
nodectr = countnode(start);
if(pos > 1 && pos < nodectr)
{
temp = prev = start;
while(ctr < pos)
{
prev = temp;
temp = temp -> next;
ctr++;
}
prev -> next = newnode;
newnode -> next = temp;
}
else
{
printf("position %d is not a middle position", pos);
}
}
229
Deletion
In a single linked list, the deletion operation can be performed in three ways. They are as
follows...
Deleting from Beginning of the list
Deleting from End of the list
Deleting a Specific Node
Deleting from Beginning of the list
We can use the following steps to delete a node from beginning of the single linked list...
Step 1: Check whether list is Empty (head == NULL)
Step 2: If it is Empty then, display 'List is Empty!!! Deletion is not possible' and terminate
the function.
Step 3: If it is Not Empty then, define a Node pointer 'temp' and initialize with head.
Step 4: Check whether list is having only one node (temp → next == NULL)
Step 5: If it is TRUE then set head = NULL and delete temp (Setting Empty list conditions)
Step 6: If it is FALSE then set head = temp → next, and delete temp.
230
Step 1: Check whether list is Empty (head == NULL)
Step 2: If it is Empty then, display 'List is Empty!!! Deletion is not possible' and terminate
the function.
Step 3: If it is Not Empty then, define two Node pointers 'temp1' and 'temp2' and initialize
'temp1' with head.
Step 4: Check whether list has only one Node (temp1 → next == NULL)
Step 5: If it is TRUE. Then, set head = NULL and delete temp1. And terminate the function.
(Setting Empty list condition)
Step 6: If it is FALSE. Then, set 'temp2 = temp1 ' and move temp1 to its next node. Repeat
the same until it reaches to the last node in the list. (until temp1 → next == NULL)
Step 7: Finally, Set temp2 → next = NULL and delete temp1.
231
Step 8: If list contains multiple nodes, then check whether temp1 is the first node in the list
(temp1 == head).
Step 9: If temp1 is the first node then move the head to the next node (head = head → next)
and delete temp1.
Step 10: If temp1 is not first node then check whether it is last node in the list (temp1 →next ==
NULL).
Step 11: If temp1 is last node then set temp2 → next = NULL and delete temp1 (free(temp1)).
Step 12: If temp1 is not first node and not last node then set temp2 → next = temp1 →next and
delete temp1 (free(temp1)).
232
int data;
struct slinklist *next;
};
typedef struct slinklist node;
node *start = NULL;
int menu()
{
int ch;
clrscr();
printf("\n [Link] a list ");
printf("\n ");
printf("\n [Link] a node at beginning ");
printf("\n [Link] a node at end");
printf("\n [Link] a node at middle");
printf("\n ");
printf("\n [Link] a node from beginning");
printf("\n [Link] a node from Last");
printf("\n [Link] a node from Middle");
printf("\n ");
printf("\n [Link] the list (Left to Right)");
printf("\n [Link] the list (Right to Left)");
printf("\n ");
printf("\n 10. Count nodes ");
printf("\n 11. Exit ");
printf("\n\n Enter your choice: ");
scanf("%d",&ch);
return ch;
}
node* getnode()
{
node * newnode;
233
newnode = (node *) malloc(sizeof(node));
printf("\n Enter data: ");
scanf("%d", &newnode -> data);
newnode -> next = NULL;
return newnode;
}
int countnode(node *ptr)
{
int count=0;
while(ptr != NULL)
{
count++;
ptr = ptr -> next;
}
return (count);
}
void createlist(int n)
{
int i;
node *newnode;
node *temp;
for(i = 0; i < n; i++)
{
newnode = getnode();
if(start == NULL)
{
start = newnode;
}
else
{
temp = start;
234
while(temp -> next != NULL)
temp = temp -> next;
temp -> next = newnode;
}
}
}
void traverse()
{
node *temp;
temp = start;
printf("\n The contents of List (Left to Right): \n");
if(start == NULL)
{
printf("\n Empty List");
return;
}
else
{
while(temp != NULL)
{
printf("%d-->", temp -> data);
temp = temp -> next;
}
}
printf(" X ");
}
void rev_traverse(node *start)
{
if(start == NULL)
{
return;
235
}
else
{
rev_traverse(start -> next);
printf("%d -->", start -> data);
}
}
void insert_at_beg()
{
node *newnode;
newnode = getnode();
if(start == NULL)
{
start = newnode;
}
else
{
newnode -> next = start;
start = newnode;
}
}
void insert_at_end()
{
node *newnode, *temp;
newnode = getnode();
if(start == NULL)
{
start = newnode;
}
else
{
236
temp = start;
while(temp -> next != NULL)
temp = temp -> next;
temp -> next = newnode;
}
}
void insert_at_mid()
{
node *newnode, *temp, *prev;
int pos, nodectr, ctr = 1;
newnode = getnode();
printf("\n Enter the position: ");
scanf("%d", &pos);
nodectr = countnode(start);
if(pos > 1 && pos < nodectr)
{
temp = prev = start;
while(ctr < pos)
{
prev = temp;
temp = temp -> next;
ctr++;
}
prev -> next = newnode;
newnode -> next = temp;
}
else
printf("position %d is not a middle position", pos);
}
void delete_at_beg()
{
237
node *temp;
if(start == NULL)
{
printf("\n No nodes are exist..");
return ;
}
else
{
temp = start;
start = temp -> next;
free(temp);
printf("\n Node deleted ");
}
}
void delete_at_last()
{
node *temp, *prev;
if(start == NULL)
{
printf("\n Empty List..");
return ;
}
else
{
temp = start;
prev = start;
while(temp -> next != NULL)
{
prev = temp;
temp = temp -> next;
}
238
prev -> next = NULL;
free(temp);
printf("\n Node deleted ");
}
}
void delete_at_mid()
{
int ctr = 1, pos, nodectr;
node *temp, *prev;
if(start == NULL)
{
printf("\n Empty List..");
return ;
}
else
{
printf("\n Enter position of node to delete: ");
scanf("%d", &pos);
nodectr = countnode(start);
if(pos > nodectr)
{
printf("\nThis node doesnot exist");
}
if(pos > 1 && pos < nodectr)
{
temp = prev = start;
while(ctr < pos)
{
prev = temp;
temp = temp -> next;
ctr ++;
239
}
prev -> next = temp -> next;
free(temp);
printf("\n Node deleted..");
}
else
{
printf("\n Invalid position..");
getch();
}
}
}
void main(void)
{
int ch, n;
clrscr();
while(1)
{
ch = menu();
switch(ch)
{
case 1:
if(start == NULL)
{
printf("\n Number of nodes you want to create: ");
scanf("%d", &n);
createlist(n);
printf("\n List created..");
}
else
printf("\n List is already created..");
240
break;
case 2:
insert_at_beg();
break;
case 3:
insert_at_end();
break;
case 4:
insert_at_mid();
break;
case 5:
delete_at_beg();
break;
case 6:
delete_at_last();
break;
case 7:
delete_at_mid();
break;
case 8:
traverse();
break;
case 9:
printf("\n The contents of List (Right to Left): \n");
rev_traverse(start);
printf(" X ");
break;
case 10:
printf("\n No of nodes : %d ", countnode(start));
break;
case 11 :
241
exit(0);
}
getch();
}
}
242
newnode = getnode();
If the list is empty, assign new node as start.
start = newnode;
If the list is not empty, follow the steps given below:
temp = start;
while(temp -> next != NULL)
temp = temp -> next;
temp -> next = newnode;
repeat the above steps n times
newnode -> next = start;
The following steps are to be followed to insert a new node at the beginning of the
circular list:
Get the new node using getnode().
newnode = getnode();
If the list is empty, assign new node as start.
start = newnode;
newnode -> next = start;
If the list is not empty, follow the steps given below:
last = start;
while(last -> next != start)
last = last -> next;
newnode -> next = start;
start = newnode;
last -> next = start;
243
The following steps are followed to insert a new node at the end of the list:
Get the new node using getnode().
newnode = getnode();
If the list is empty, assign new node as start.
start = newnode;
newnode -> next = start;
If the list is not empty follow the steps given below:
temp = start;
while(temp -> next != start)
temp = temp -> next;
temp -> next = newnode;
newnode -> next = start;
244
The following steps are followed, to delete a node at the beginning of the list:
IF the list is empty, Display the message “ circular linked list is empty”
If the list is not empty, follow the steps given below:
last = temp = start;
while(last -> next != start)
last = last -> next;
start = start -> next;
last -> next = start;
After deleting the node, if the list is empty then start = NULL.
The following steps are followed to delete a node at the end of the list:
IF the list is empty, Display the message “ circular linked list is empty”
If the list is not empty, follow the steps given below:
temp = start;
prev = start;
while(temp -> next != start)
{
prev = temp;
temp = temp -> next;
}
prev -> next = start;
After deleting the node, if the list is empty then start = NULL.
245
13.4 DOUBLY LINKED LIST
A double linked list is a two-way list in which all nodes will have two links. This helps in accessing
both successor node and predecessor node from the given node position. It provides bi-directional
traversing. Each node contains three fields:
Left link.
Data.
Right link.
The left link points to the predecessor node and the right link points to the successor node. The
data field stores the required data.
Here, 'link1' field is used to store the address of the previous node in the sequence, 'link2' field is
used to store the address of the next node in the sequence and 'data' field is used to store the
actual value of that node.
In double linked list, the first node must be always pointed by head.
Always the previous field of the head node must be NULL.
Always the next field of the last node must be NULL.
246
Many applications require searching forward and backward thru nodes of a list.
For example searching for a name in a telephone directory would need forward and backward
scanning thru a region of the whole list.
The basic operations in a double linked list are:
Creation.
Insertion.
Deletion.
Traversing.
To create a node, the structure is :
247
The previous nodes right field must be assigned with address of the new node.
Repeat the above steps n times.
13.5 SUMMARY
In this unit, we studied about variants of linked list like singly linked list, doubly linked list, circular
linked list and the operations that are performed on these data structures. The implementation of
singly linked list is also studied. The common operations performed on linked list are creation,
insertion, deletion, display operations. Linked List is a very commonly used linear data structure
which consists of set of nodes in a sequence. Each node has two fields known as data and link.
Data field stores actual data and link contains address of next node to point to the next node.
Linked Lists are used to create trees and graphs.
13.6 SUMMARY
Linked list,
singly linked list,
doubly linked list,
circular linked list,
2. Write the structure of a node of singly linked list and its implementation in C .
4. Explain the steps to insert an element at the beginning of a singly linked list with example.
248
5. Explain the steps to insert an element at the end of a singly linked list with example.
6. Explain the steps to insert an element at the middle of a singly linked list with example.
13.8 REFERENCES
249
UNIT 14
Structure:
14.0 Objectives
14.1 Introduction
14.2 Stack
14.3 QUEUE
14.6 Summary
14.7 Keywords
14.9 References
14.0 OBJECTIVES
14.1 INTRODUCTION
There are certain situations in computer science that one wants to restrict insertions and deletions so that
they can take place only at the beginning or the end of the list, not in the middle. Two of such data
structures that are useful are: Stack.
Queue.
250
Linear lists and arrays allow one to insert and delete elements at any place in the list i.e., at the beginning,
at the end or in the middle. Stack follows FIFO rule. The insertion and deletion is restricted to one end.
The operation of insertion is called PUSH and deletion operation is called POP. There will be a pointer
called TOP pointing to the top most element of the stack which will be the element to be deleted from
stack. During insertion, the top pointer will be increment by one and the element is inserted. After deletion,
the top pointer will be decremented by one.
Queue is a data structure which follows LIFO rule. The insertion will be from the rear end and deletion
will be from the front end. Hence there are two pointers front and rear pointing to front and rear end.
During insertion, rear pointer is incremented by one. After deleting the front element, the front pointer is
updated to point to the next element.
14.2 STACK
A stack is a list of elements in which an element may be inserted or deleted only at one end, called
the top of the stack. Stacks are sometimes known as LIFO (last in, first out) [Link] the items can be
added or removed only from the top i.e. the last item to be added to a stack is the first item to be removed.
The two basic operations associated with stacks are: Push: is
the term used to insert an element into a stack. Pop: is the
term used to delete an element from a stack. Fig 14.2.1
251
All insertions and deletions take place at the same end, so the last element added to the stack will be the
first element removed from the stack. When a stack is created, the stack base remains fixed while the
stack top changes as elements are added and removed. The most accessible element is the top and the least
accessible element is the bottom of the stack. Let us consider a stack with 6 elements capacity. This is
called as the size of the stack. The number of elements to be added should not exceed the maximum size of
the stack. If we attempt to add new element beyond the maximum size, we will encounter a stack
overflow condition. Similarly, you cannot remove elements beyond the base of the stack. If such is the
case, we will reach a stack underflow condition. When an element is added to a stack, the operation is
performed by push (). Figure shows the creation of a stack and addition of elements using push (). During
insertion, the top pointer is incremented and to the new location, element is pushed. Fig 14.2.2
When an element is taken off from the stack, the operation is performed by pop (). Figure shows a stack
initially with three elements and shows the deletion of elements using pop (). The element pointed by top
pointer is deleted. Fig 14.2.3
252
Applications of stacks:
1. Stack is used by compilers to check for balancing of parentheses, brackets and braces.
2. Stack is used to evaluate a postfix expression.
3. Stack is used to convert an infix expression into postfix/prefix form.
4. In recursion, all intermediate arguments and return values are stored on the stack.
5. During a function call the return address and arguments are pushed onto a stack and on return
they are popped off.
Algorithm for PUSH:
NOTE:During insertion, we check for overflow condition. This condition arises if stack is [Link] the stack
is not full, then top pointer is incremented by one. The element is inserted.
NOTE:During deletion, we check for underflow condition. This condition arises if the stack is empty. If
the stack is note empty, then the element pointed by top pointed is accessed and copied to data. Top
pointer is decremented by one.
253
14.3 QUEUE
Queue is a data structure. Unlike stacks, a queue is open at both its ends. One end is always used to insert
data (enqueue) and the other is used to remove data (dequeue). Queue follows First-In- First-Out
methodology, i.e., the data item stored first will be accessed first. Fig 14.3.1
Here two pointers front and rear are used. During insertion, rear pointer is incremented by one and the
element is inserted. During deletion, the front pointer is incremented to point to the next element after
[Link] stack, during insertion we have to check form overflow condition and during deletion, we
have to check for queue underflow condition.
OVERFLOW condition occurs when rear pointer value is equal to maximum size of queue.
UNDERFLOW condition occurs when both front and rear pointers have same value.
Applications of Queue:
1. It is used to schedule the jobs to be processed by the CPU.
2. When multiple users send print jobs to a printer, each printing job is kept in
the printing queue. Then the printer prints those jobs according to first in
first out (FIFO) basis.
3. Breadth first search uses a queue data structure to find an element from a
graph.
254
QUEUE Representation:
Let us consider a queue, which can hold maximum of five elements. Initially the queue is empty. So both
1. Insert 11.
2. Insert 22
3. insert 33
4. Delete 11
5. Delete 22
255
6. Insert 44 and 55
7. Insert 66
It is not possible , because Rear pointer has reached the end. So even though , space is available
in the front end, we cannot insert the element, once the rear pointer reaches the end. This type of
queue is called linear queue.
The following steps should be taken to enqueue (insert) data into a queue −
Step 1 − Check if the queue is full.
Step 2 − If the queue is full, produce overflow error and exit.
Step 3 − If the queue is not full, increment rear pointer to point the next empty space.
step 4- If the queue is empty, then increment front pointer also.
Step 5 − Add data element to the queue location, where the rear is pointing.
Step 6 − Return success.
QUEUE DELETION:
Accessing data from the queue is a process of two tasks − access the data where front is
pointing and remove the data after access. The following steps are taken to perform dequeue
operation −
Step 1 − Check if the queue is empty.
Step 2 − If the queue is empty, produce underflow error and exit.
256
Step 3 − If the queue is not empty, access the data where front is pointing.
Step 4- If the queue has only one element, set both front and rear pointer to zero after deletion.
Step 5 − Otherwise;Increment front pointer to point to the next available data element.
# include <stdio.h> #
include <conio.h> #
include <stdlib.h> #
define MAX 6
int stack[MAX];
int top = 0;
int menu()
{
int ch;
clrscr();
printf("\Stack operation using array\n”); printf("\n
-----------********** ------------------------------ \n");
printf("\n 1. Push ");
printf("\n 2. Pop ");
printf("\n 3. Display");
printf("\n 4. Quit ");
printf("\n Enter your choice: ");
scanf("%d", &ch);
return ch;
}
void display()
{
int i;
if(top == 0)
{
printf("\n\nStack empty..");
return;
}
else
{
printf("\n\nElements in stack:");
257
for(i = 0; i < top; i++)
printf("\t%d", stack[i]);
}
}
void pop()
{
if(top == 0)
{
printf("\n\nStack Underflow..");
return;
}
else
printf("\n\npopped element is: %d ", stack[--top]);
}
void push()
{
int data;
if(top == MAX)
{
printf("\n\nStack Overflow..");
return;
}
else
{
printf("\n\nEnter data: ");
scanf("%d", &data);
stack[top] = data;
top = top + 1;
printf("\n\nData Pushed into the stack");
}
}
void main()
{
int ch;
do
{
ch = menu();
switch(ch)
{
case 1:
push();
break;
case 2:
pop();
break;
case 3:
258
display();
break;
case 4:
exit(0);
}
getch();
} while(1);
}
In order to create a queue we require a one dimensional array Q(1:n) and two variables front and rear.
The conventions we shall adopt for these two variables are that front is always 1 less than the actual front of
the queue and rear always points to the last element in the queue. Thus, front =rear if and only if there are
no elements in the queue. The initial condition then is front = rear =
0. The various queue operations to perform creation, deletion and display the elements in a queue
are as follows:
1. insertQ(): inserts an element at the end of queue Q.
2. deleteQ(): deletes the first element of Q.
3. displayQ(): displays the elements in the queue.
# include <conio.h>
# define MAX 6
int Q[MAX]; int
front, rear; void
insertQ()
{
int data;
if(rear == MAX)
{
printf("\n Linear Queue is full");
return;
}
else
{
printf("\n Enter data: ");
scanf("%d", &data);
Q[rear] = data;
rear++;
printf("\n Data Inserted in the Queue ");
259
}
}
void deleteQ()
{
if(rear == front)
{
printf("\n\n Queue is Empty..");
return;
}
else
{
printf("\n Deleted element from Queue is %d",
Q[front]); front++;
}
}
void displayQ()
{
int i;
if(front == rear)
{
printf("\n\n\t Queue is Empty");
return;
}
else
{
printf("\n Elements in Queue are: ");
for(i = front; i < rear; i++)
{
printf("%d\t", Q[i]);
}
}
}
int menu()
{
int ch;
clrscr();
printf("\n \tQueue operations using ARRAY..");
printf("\n -----------********** ------------------ \n");
printf("\n 1. Insert ");
printf("\n 2. Delete ");
printf("\n 3. Display");
printf("\n 4. Quit ");
printf("\n Enter your choice: ");
scanf("%d", &ch);
return ch;
260
}
void main()
{
int ch;
do
{
ch = menu();
switch(ch)
{
case 1:
insertQ();
break;
case 2:
deleteQ();
break; case
3:
displayQ();
break;
case 4:
return;
}
getch();
} while(1);
}
We can represent a stack as a linked list. In a stack push and pop operations are performed at one end
called top. We can perform similar operations at one end of list using top pointer. The linked stack looks
as shown in figure 14.5.1
# include <conio.h> #
include <stdlib.h>
261
struct stack
{
int data;
struct stack *next;
};
void push();
void pop(); void
display();
typedef struct stack node; node
*start=NULL;
node *top = NULL;
node* getnode()
{
node *temp;
temp=(node *) malloc( sizeof(node)) ;
printf("\n Enter data ");
scanf("%d", &temp -> data);
temp -> next = NULL; return
temp;
}
void push(node *newnode)
{
node *temp;
if( newnode == NULL )
{
printf("\n Stack Overflow..");
return;
}
{
start = newnode;
top = newnode;
}
else
{
temp = start;
while( temp -> next != NULL)
temp = temp -> next;
temp -> next = newnode;
top = newnode;
}
printf("\n\n\t Data pushed into stack");
}
void pop()
{
node *temp;
262
if(top == NULL)
{
printf("\n\n\t Stack underflow");
return;
}
temp = start;
if( start -> next == NULL)
{
printf("\n\n\t Popped element is %d ", top -> data); start =
NULL;
free(top); top
= NULL;
}
else
{
while(temp -> next != top)
{
temp = temp -> next;
}
temp -> next = NULL;
printf("\n\n\t Popped element is %d ", top -> data); free(top);
top = temp;
}
}
void display()
{
node *temp;
if(top == NULL)
{
printf("\n\n\t\t Stack is empty ");
}
else
{
temp = start;
printf("\n\n\n\t\t Elements in the stack: \n");
printf("%5d ", temp -> data);
while(temp != top)
{
temp = temp -> next; printf("%5d
", temp -> data);
}
}
}
char menu()
{
263
char ch;
clrscr();
printf("\n \tStack operations using pointers.. ");
printf("\n -----------********** ------------------ \n");
printf("\n 1. Push ");
printf("\n 2. Pop ");
printf("\n 3. Display");
printf("\n 4. Quit ");
printf("\n Enter your choice: "); ch
= getche();
return ch;
}
void main()
{
char ch;
node *newnode;
do
{
ch = menu();
switch(ch)
{
case '1' :
newnode = getnode();
push(newnode); break;
case '2' :
pop();
break;
case '3' :
display();
break;
case '4':
return;
}
getch();
} while( ch != '4' );
}
QUEUE IMPLEMENTATION USING LINKED LIST:
We can represent a queue as a linked list. In a queue data is deleted from the front end and inserted at the
rear end. We can perform similar operations on the two ends of a list. We use two pointers front and rear
for our linked queue implementation
14.5.2
264
# include <stdlib.h> #
include <conio.h>
struct queue
{
int data;
struct queue *next;
};
typedef struct queue node;
node *front = NULL; node
*rear = NULL; node*
getnode()
{
node *temp;
temp = (node *) malloc(sizeof(node)) ;
printf("\n Enter data ");
scanf("%d", &temp -> data);
temp -> next = NULL; return
temp;
}
void insertQ()
{
node *newnode;
newnode = getnode();
if(newnode == NULL)
{
printf("\n Queue Full");
return;
}
if(front == NULL)
{
front = newnode;
rear = newnode;
}
else
{
rear -> next = newnode;
rear = newnode;
}
printf("\n\n\t Data Inserted into the Queue..");
265
}
void deleteQ()
{
node *temp; if(front
== NULL)
{
printf("\n\n\t Empty Queue..");
return;
}
temp = front;
front = front -> next;
printf("\n\n\t Deleted element from queue is %d ", temp -> data);
free(temp);
}
void displayQ()
{
node *temp; if(front
== NULL)
{
printf("\n\n\t\t Empty Queue ");
}
else
{
temp = front;
printf("\n\n\n\t\t Elements in the Queue are: ");
while(temp != NULL )
{
printf("%5d ", temp -> data); temp
= temp -> next;
}
}
}
char menu()
{
char ch;
clrscr();
printf("\n \t..Queue operations using pointers.. ");
printf("\n\t -----------**********-------------
\n"); printf("\n 1. Insert ");
printf("\n 2. Delete ");
printf("\n 3. Display");
printf("\n 4. Quit ");
printf("\n Enter your choice: "); ch
= getche();
return ch;
}
266
void main()
{
char ch;
do
{
ch = menu();
switch(ch)
{
case '1' :
insertQ();
break; case
'2' :
deleteQ();
break; case
'3' :
displayQ();
break;
case '4':
return;
}
getch();
} while(ch != '4');
}
14.6 SUMMARY
In this unit, we studied about stack, queue and their implementation using array and linked
[Link] queue which we studied is called linear queue. The stack has only one pointer called
top. It points to the top most element of the stack. Insertion is called PUSH and deletion
operation is called POP. Whereas queue has two pointers front and [Link] stack, insertion and
deletion operations are done from only one end.
14.7 KEYWORDS
Stack
queue
top
rear
267
14.8 QUESTIONS FOR SELF STUDY
14.9 REFERENCES
268
UNIT 15
RECURSION
Structure:
15.0 Objectives
15.1 Introduction
15.2 Recursion
15.4 Summary
15.5 Keywords
15.7 References
15.0 OBJECTIVES
Explain Recursion
Explain recursive algorithm to find factorial of a number
Write recursive algorithm to find GCD of a number
15.1 INTRODUCTION
A function is recursive if a statement in the body of the function calls itself. Recursion is the process of
defining something in terms of itself. For a computer language to be recursive, a function must be able to
call itself.
269
15.2 RECURSION
A function is recursive if a statement in the body of the function calls itself. Recursion is the process of
defining something in terms of itself. For a computer language to be recursive, a function must be able to
call itself.
Recursive function: calling a function by itself until the given terminal condition is satisfied is called
recursion and the function is called recursive function.
When a function calls itself, new local variables and parameters are allocated storage on the stack
and the function code is executed with these new variables from the start.
A recursive call does not make a new copy of the function. Only the arguments and variables are new. As
each recursive call returns, the old local variables and parameters are removed from the stack and
execution resumes at the point of the function call inside the function.
When writing recursive functions, you must have an exit or terminal condition somewhere to force the
function to return without the recursive call being executed. If you do not have an exit condition, the
recursive function will recurse forever until you run out of stack space and indicate error about lack of
memory, or stack overflow.
Syntax
void recurse()
{
… .. …
recurse(); /* calling of the function by itself */
… .. …
}
270
int main()
{
… .. …
recurse();
… .. …
}
int factorial(int x)
if(x <= 1)
return 1;
int main()
int x = 12;
0;
OUTPUT:
The factorial of the number 12 is equal to 479001600
271
Here the function factorial is called recursively until the terminal condition (x<=1) is satisfied. Recursion
Factorials:
5! =5 * 4! = 5 * = factorial (5) = 5 * factorial (4) =
4! = 4 *3! = 4 * = _ factorial (4) = 4 * factorial (3) =
3! = 3 * 2! = 3 * = _ factorial (3) = 3 * factorial (2) =
2! = 2 * 1! = 2 * = _ factorial (2) = 2 * factorial (1) =
1! = 1
5! = 5*4! = 5*4*3! = 5*4*3*2! = 5*4*3*2*1! = 5*4*3*2*1*0! = 5*4*3*2*1*1=120
Example 2:
OUTPUT:
Enter two positive integers: 366 60
G.C.D of 366 and 60 is 6.
Example 3:
To print Fibonacci series using recursion
#include<stdio.h>
void printFibonacci(int n){
static int n1=0,n2=1,n3;
272
if(n>0){
n3 = n1 + n2;
n1 = n2;
n2 = n3; printf("%d
",n3);
printFibonacci(n-1);
}
}
int main(){
int n;
printf("Enter the number of elements: ");
scanf("%d",&n);
printf("Fibonacci Series: ");
printf("%d %d ",0,1);
printFibonacci(n-2);//n-2 because 2 numbers are already printed return
0;
}
OUTPUT:
Enter the number of elements: 10 Fibonacci
Series: 0 1 1 2 3 5 8 13 21 34
273
Syntax
int main()
{
}
The function call inside the main function is normal call, it calls the recursive fun () function
inside which there is another function call recursive fun (); which is termed as recursive call and
the whole recursive fun () function is recursive function. Base case is the stopping condition for
the recursive function.
How does Recursion in C work?
The recursion is possible using a method or function in C language. The recursive function or
method has two main parts in its body, i.e., the base case and the recursive case. While
the recursive method is executed, first, the base case is checked by the program. If it turns out
true, the function returns and quits; otherwise, the recursive case is executed. Inside the
recursive case, we have a recursive call that calls the function inside which it is present. The
representation of recursion in the program is as follows.
recursive_function()
{
//base case
if base_case = true;
return;
else
//recursive case
return code_for_recursion; //includes recursive call
}
In the following image, there is a recursive function inside which there is a recursive call that
calls the recursive function until the condition of the problem is true. If the condition gets
satisfied, then the condition is false, and the program control goes for the remaining statements
and stops the program. Fig 15.3.1
274
Types of Recursions in C
1. Direct Recursion
2. Indirect Recursion
1. Direct Recursion
Direct recursion in C occurs when a function calls itself directly from inside. Such functions are also called
direct recursive functions. Following is the structure of direct recursion.
function_01()
{
//some code
function_01();
//some code
}
275
In the direct recursion structure, the function_01() executes, and from inside, it calls
itself recursively.
2. Indirect Recursion
Indirect recursion in C occurs when a function calls another function and if this
function calls the first function again. Such functions are also called indirect
recursive functions. Following is the structure of indirect recursion.
function_01()
{
//some code
function_02();
}
function_02()
{
//some code
function_01();
}
In this unit, we studied about recursion. Recursion is calling a function by itself repeatedly till some exit
condition is satisfied. When a function calls itself, new local variables and parameters are allocated
storage on the stack and the function code is executed with these new variables from the start. A recursive
call does not make a new copy of the function. Only the arguments and variables are new. As each
recursive call returns, the old local variables and parameters are removed from the stack and execution
resumes at the point of the function call inside the function.
15.5 KEYWORDS
Recursion
exit
condition
276
15.6: QUESTION FOR SELF STUDY
1. Define recursion.
15.7: REFERENCES
277
UNIT -16
STRUCTURE AND UNION
Structure:
16.0 Objectives
16.1 Introduction
16.2 Structure
16.3 Union
16.6 Summary
16.7 Keywords
16.0 OBJECTIVES
16.1 INTRODUCTION
Structure is a collection of data items of different data types under a common name. Whereas array is a
collection of data items of same data type. Union is a collection of data items of different data types
similar to structure but in this case all the members share a common memory location. The size of the
union corresponds to the length of the largest member. Although C does not provide direct support to
error handling (or exception handling), there are ways through which error handling can be done in C. A
programmer has to prevent errors in the first place and test return values from the functions.
278
When the address of the value is passed to the function it is called call by reference. In call by
reference since the address of the value is passed any changes made to the value reflects in the calling
function. In call by reference, pointers are used to refer to the address of values.
16.2 STRUCTURE
A structure is a user defined data type. We know that arrays can be used to represent a group of data items
that belong to the same type, such as int or float. However, we cannot use an array if we want to represent
a collection of data items of different types using a single name.A structure is a convenient tool for
handling a group of logically related data items. Structure is a user defined data type used to represent a
group of data items of different types using a single name.
The syntax of structure declaration is
struct structure_name
type element 1;
type element 2;
……………..
type element n;
};
In structure declaration the keyword struct appears first, this followed by structure name. The
member of structure should be enclosed between a pair of braces and it defines one by one each ending
with a semicolon. It can also be array of structure. There is an enclosing brace at the end of declaration
and it end with a semicolon.
We can declare structure variables as follows struct
structure_name var1,var2,…..,var n; Example:
To store the names, roll number and total mark of a student you can declare 3 variables. To store
this data for more than one student 3 separate arrays may be declared. Another choice is to make a
structure. No memory is allocated when a structure is declared. It just defines the “form” of the structure.
When a variable is made then memory is allocated. This is equivalent to
279
saying that there's no memory for “int”, but when we declare an integer that is int var; only then memory
is allocated.
The structure for the abovementioned case will look like struct
student
{
int rollno;
char name[25];
float totalmark; };
We can now declare structure variables stud1, stud2 as follows struct
student stud1,stud2;
280
{
char *name;
int rollno;
float totalmark;
};
struct student stud1={"Venkat",1,98}; struct
student stud3= {"Shweta",3,97}; struct
student stud2={"Arpita",2,99}; clrscr();
printf(“STUDENTS DETAILS:\n”);
printf(“\n\n Roll number:%d\n Name:%s\n Total Marks:%f”, [Link], [Link], [Link]);
printf(“\n\n Roll number:%d\n Name:%s\n Total Marks:%f”, [Link], [Link], [Link]);
printf(“\n\n Roll number:%d\n Name:%s\n Total Marks:%f”, [Link], [Link], [Link]);
getch();
}
Output
STUDENTS DETAILS:
Roll number: 1 Name:
Venkat
Total Marks:98.000000
Roll number: 2
Name: Arpita
Total Marks:99.000000
Roll number: 2
Name:Shweta
Total Marks:99.000000
Array of structures:
281
It is possible to store a structure has an array element. i.e., an array in which each element is a structure.
Just as arrays of any basic type of variable are allowed, so are arrays of a given type of structure.
Although a structure contains many different types, the compiler never gets to know this information
because it is hidden away inside a sealed structure capsule, so it can believe that all the elements in the
array have the same type, even though that type is itself made up of lots of different types.
282
{
struct student
{
int rollno;
char name[25];
int totalmark;
}stud[100];
int n,i;
clrscr();
printf("Enter total number of students\n\n");
scanf("%d",&n);
for(i=0;i<n;i++)
{
printf("Enter details of %d-th student\n",i+1);
printf("Name:\n"); scanf("%s",&stud[i].name);
printf("Roll number:\n");
scanf("%d",&stud[i].rollno);
printf("Total mark:\n");
scanf("%d",&stud[i].totalmark);
}
printf("STUDENTS DETAILS:\n");
for(i=0;i<n;i++) { printf("\nRoll number:%d\n",stud[i].rollno);
printf("Name:%s\n",stud[i].name);
printf("Total mark:%d\n",stud[i].totalmark);
}
getch();
}
OUTPUT
Enter total number of students: 3
283
Enter details of 1-th student
Name:SUBAHAS
Roll number:11
Total mark:589
Enter details of 2-th student
Name:RUKSANA
Roll number:12
Total mark:594
Enter details of 3-th student
Name:SANA
Roll number:13
Total mark:595
STUDENTS DETAILS:
Roll number:11
Name: SUBAHAS
Total mark:589 Roll
number:12 Name:
RUKSANA
Total mark:594
Roll number:13
Name: SANA
Total mark:595
16.3 UNION
Union is a user created data type similar to structure but in this case all the members share a common
memory location. The size of the union corresponds to the length of the largest member. Since the
member share a common location, they have the same starting address. The real purpose of unions is to
prevent memory fragmentation by arranging for a standard size for data in the memory. By having a
standard data size, we can guarantee that any hole left when dynamically allocated memory is freed will
always be reusable by another instance of the same type of union. This is a natural strategy in system
programming where many instances of different kinds of variables with a related purpose and stored
dynamically.
284
A union is declared in the same way as a structure. The syntax of union declaration is
union union_name
{
type element 1;
type element 2;
……………..
type element n;
};
This declares a type template.
Variables are then declared as:
union union_name x,y,z;
For example, the following code declares a union data type called Student and a union variable called
stud:
union student
{
int rollno;
float totalmark;
};
union student stud;
It is possible to combine the declaration of union combination with that of the union variables, as shown
below.
union union_name
{
type element 1;
type element 2;
……………..
type element n;
}var1,var2,…,varn;
The following single declaration is equivalent to the two declaration presented in the previous example.
union student
285
{
int rollno;
float totalmark;
}x,y,z;
Example
union shared
{
char c;
int i;
};
shared.c =’a’;
shared.d=1;
In this case, value assignment to member variable (d) overwrites the member variable(c).
286
Difference between Structure and Union
287
Syntax
data_type *var_name;
Example :
int *p; char *p;
Where, * is used to denote that ―p is pointer variable and not a normal variable.
Key points to remember about pointers in C:
Normal variable stores the value whereas pointer variable stores the address of the variable.
The content of the C pointer always be a whole number i.e. address.
Always C pointer is initialized to null, i.e. int *p = null.
The value of null pointer is 0.
& symbol is used to get the address of the variable.
symbol is used to get the value of the variable that the pointer is pointing to.
If pointer is assigned to NULL, it means it is pointing to nothing.
The size of any pointer is 2 byte (for 16 bit compiler).
No two pointer variables should have the same name.
But a pointer variable and a non-pointer variable can have the same name.
Pointer –Initialization:
Assigning value to pointer:
It is not necessary to assign value to pointer. Only zero (0) and NULL can be assigned to a pointer
no other number can be assigned to a pointer.
Consider the following examples; int
*p=0;
int *p=NULL; The above two assignments are valid. int
*p=1000; This statement is invalid.
Assigning variable to a pointer:
int x; *p;
p = &x;
This is nothing but a pointer variable p is assigned the address of the variable x. The address of the
variables will be different every time the program is executed.
Reading value through pointer:
int x=123; *p; p
= &x;
288
Here the pointer variable p is assigned the address of variable x.
printf(―%d‖, *p); will display value of x 123. This is reading value through pointer
printf(―%d‖, p); will display the address of the variable x.
printf(―%d‖, &p); will display the address of the pointer variable p.
printf(―%d‖,x); will display the value of x 123.
printf(―%d‖, &x); will display the address of the variable x.
Note: It is always a good practice to assign pointer to a variable rather than 0 or NULL.
Pointer Assignments:
We can use a pointer on the right-hand side of an assignment to assign its value to another
variable.
Example:
int main()
{
int var=50;
int *p1, *p2;
p1=&var;
p2=p1;
}
Function pointer in C:
In C, like normal data pointers (int *, char *, etc), we can have pointers to functions. Following is a
simple example that shows declaration and function call using function pointer.
#include <stdio.h>
// A normal function with an int parameter
// and void return type void
fun(int a)
{
printf("Value of a is %d\n", a);
}
int main()
{
// fun_ptr is a pointer to function fun()
289
void (*fun_ptr)(int) = &fun;
/* The above line is equivalent of following two void
(*fun_ptr)(int);
fun_ptr = &fun;
*/
// Invoking fun() using fun_ptr
(*fun_ptr)(10);
return 0;
}
Output:
Value of a is 10
1) Unlike normal pointers, a function pointer points to code, not data. Typically a function
pointer stores the start of executable code.
2) Unlike normal pointers, we do not allocate de-allocate memory using function pointers.
3) A function’s name can also be used to get functions’ address. For example, in the below
program, we have removed address operator ‘&’ in assignment. We have also changed
function call by removing *, the program still works.
#include <stdio.h>
// A normal function with an int parameter
// and void return type void
fun(int a)
{
printf("Value of a is %d\n", a);
}
int main()
{
void (*fun_ptr)(int) = fun; // & removed
fun_ptr(10); // * removed
return 0;
}
290
Output:
Value of a is 10
As such C programming does not provide direct support for error handling but being a system
programming language, it provides you access at lower level in the form of return values. Most of the C
or even Unix function calls return -1 or NULL in case of any error and sets an error code errno is
set which is global variable and indicates an error occurred during any function call. You can find
various error codes defined in <error.h> header file.
So a C programmer can check the returned values and can take appropriate action depending on the return
value. As a good practice, developer should set errno to 0 at the time of initialization of the program. A
value of 0 indicates that there is no error in the program.
The errno, perror and strerror
The C programming language provides perror and strerror functions which can be used to display
the text message associated with errno.
The perror function displays the string you pass to it, followed by a colon, a space, and then the textual
representation of the current errno value.
The strerror function, which returns a pointer to the textual representation of the current errno value.
Let's try to simulate an error condition and try to open a file which does not exist. Here I'm using both the
functions to show the usage, but you can use one or more ways of printing your errors. Second important
point to note is that you should use stderr file stream to output all the errors. #include <stdio.h>
#include <errno.h>
#include <string.h>
extern int errno ; int
m ain ()
{
FILE * pf;
int errnum ;
pf = fopen ("[Link]", "rb");
291
if (pf == NULL)
{
errnum = errno;
fprintf(stderr, "Value of errno: %d\n", errno);
perror("Error printed by perror");
fprintf(stderr, "Error opening file: %s\n", strerror( errnum ));
}
else
{
fclose (pf);
}
return 0;
}
When the above code is compiled and executed, it produces the following result: Value of
errno: 2
Error printed by perror: No such file or directory Error
opening file: No such file or directory Divide by zero
errors
It is a common problem that at the time of dividing any number, programmers do not check if a divisor is
zero and finally it creates a runtime error.
The code below fixes this by checking if the divisor is zero before dividing: #include
<stdio.h>
#include <stdlib.h>
main()
{
int dividend = 20;
int divisor = 0; int
quotient;
if( divisor == 0){
fprintf(stderr, "Division by zero! Exiting...\n");
exit(-1);
292
}
quotient = dividend / divisor;
fprintf(stderr, "Value of quotient : %d\n", quotient ); exit(0);
}
When the above code is compiled and executed, it produces the following result: Division by
zero! Exiting...
293
16.6 SUMMARY
In this unit, we studied about structure, union, error handling and pointer to function. Structure
is a special data type. Multiple members of various data kinds can be held in a single structure.
Structure elements are stored in contiguous memory regions and may be accessed and retrieved
at any time. A member or field is a data object in a structure. A union is a data type that has
been specified by the user. It’s similar to the structure, except that all of its members begin at
the same memory position.
16.7 KEYWORDS
Structure
union
pointer
function pointer
16.9 REFERENCES
294
295