C Programming
C Programming
INTRODUCTION TO C PROGRAMMING
Structure:
1.0 Objectives
1.1 Introduction
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.
176
A computer or a system is operated by given a set of rules and instruction to perform
some task. These sat 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:
Machine Languages
Assembly Languages
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.
Eg; 101100111 is considered as a machine language instruction.
Advantages of machine level language:
Its machine dependent language i.e. individual program required for each machine.
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.
177
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.
Move a,b
Add c
Store b
Example:
#include<stdio.h>
Int a;
Scanf(“%d”, &a);
STRUCTURED PROGRAMMING
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.
179
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 world.
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
particular block of statements. This structure also follows single entry and single exit concept.
180
Example statements are: if-then, if-then-else statements, switch statement
Iteration statements:
Here the execution of certain statements will be repeated based on the value of the expression.
Example: while, do-while and for loop statements
181
7. Machine-Independent, mostly.
Disadvantages of Structured Programming Approach:
1. Since it is Machine-Independent, So it takes time to convert into machine code.
2. The converted machine code is not the same as for assembly language.
3. The program depends upon changeable factors like data-types. Therefore it needs to
be updated with the need on the go.
4. Usually the development in this approach takes longer time as it is language-
dependent. Whereas in the case of assembly language, the development takes lesser
time as it is fixed for the machine.
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), or it might require linking with other object code files (e.g. libraries) to produce a
complete executable program.
182
The compilation and execution process of C program can be divided in to multiple steps:
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
183
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 addresses.
There 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 shuld 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
1) Writing and Editing the program
2) Compiling the program
184
3) Linking the program with the required modules
4) Executing the program
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:
Precision – the steps are precisely stated (defined).
Uniqueness – results of each step are uniquely defined and only depend on the input and
the result of the preceding steps.
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
186
step 3 : rem=number mod 2
step 4 : if rem=0 then print "number even" else print "number odd" endif
step 5:stop
FLOWCHART
187
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.
188
1.2 OVERVIEW OF THE C LANGUAGE, HISTORY AND FEATURES
C is a general-purpose, procedural programming language that has had a profound impact on the
field of computer science and software development. Here's an overview of the C language,
including its history and key features:
History: C was originally developed by Dennis Ritchie at Bell Labs in the early 1970s. It was
created as an evolution of the B programming language (a simpler predecessor) and was aimed at
implementing the UNIX operating system. Dennis Ritchie, along with Ken Thompson, also
contributed to the development of UNIX, which became one of the most influential operating
systems in history.
C was designed to be a low-level language, allowing direct access to the computer's hardware
and providing efficient memory manipulation. Its design and flexibility made it suitable for
systems programming, and its portability across different platforms played a significant role in
the widespread adoption of C.
In the late 1970s and early 1980s, C was standardized by the American National Standards
Institute (ANSI) and later by the International Organization for Standardization (ISO). The
standardized version, known as ANSI C or ISO C, brought uniformity to the language and
allowed it to be used across different systems and compilers.
Features:
189
2. Portability: C programs can be written once and run on multiple platforms with minimal
modifications, making it highly portable. This portability was crucial for the development
of UNIX and other cross-platform software.
3. Efficiency and Performance: C allows direct memory manipulation through pointers,
which gives developers fine-grained control over memory usage and performance
optimizations. This efficiency makes it a popular choice for systems programming,
embedded systems, and resource-constrained environments.
4. Static Typing: C is statically typed, which means variable types need to be explicitly
declared during the compilation phase. This feature helps catch type-related errors at
compile time, leading to more robust code.
5. Rich Standard Library: C comes with a standard library that provides essential
functions for tasks like input/output operations, string manipulation, memory allocation,
mathematical computations, and more. It makes C programs more concise and efficient.
6. Pointers: C is known for its powerful pointer arithmetic, allowing developers to work
directly with memory addresses and data structures. While powerful, pointers can also be
a source of bugs and require careful management.
7. Modularity and Reusability: C supports modularity through functions and user-defined
data types, promoting code reusability and maintainability.
8. Widespread Adoption: Due to its historical significance, efficiency, and portability, C
has been used in various domains, such as operating systems, embedded systems, game
development, system-level programming, and more.
Although C has stood the test of time and remains relevant, it is not without its challenges. Being
a low-level language, C exposes developers to potential pitfalls, such as buffer overflows and
undefined behavior, which require careful coding practices and testing.
Despite these challenges, C continues to be a vital language in the software industry, and many
modern languages and frameworks have been influenced by its design principles and syntax.
Learning C provides a solid foundation for understanding programming concepts and working
closer to the hardware.
190
1.3 SUMMARY
In this unit, you have studied the Overview of the C Language, History and Features
1.4 KEYWORDS
1.7 REFERENCES
191
8. A Structured Programming Approach using C – B.A. Forouzan& R.F. Gillberg,
THOMSON Indian Edition
9. Computer fundamentals and programming in C – PradipDey&Manas Ghosh, OXFORD
10. P. K. Sinha &PritiSinha , “Computer Fundamentals”, BPB Publications, 2007.
11. Dr. Anita Goel, Computer Fundamentals, Pearson Education, 2010.
UNIT-2
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
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. 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.
2.2 THE C LANGUAGE AND ITS ADVANTAGES
C is the most popular programming language, C has many advantages
1. Modularity.
2. Portability.
3. Extendibility.
4. Speed.
5. Flexibility.
193
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 feature
it 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.
2.3 STRUCTURE OF A C PROGRAM
C language is very popular language among all the languages. The structure of a C program is a
protocol (rules) to the programmer, while writing a C program. The general basic structure of C
program is shown in the figure below. The whole program is controlled within main ( ) along
with left brace denoted by “{” and right braces denoted by “}”. If you need to declare local
variables and executable program structures are enclosed within “{” and “}” is called the body of
the main function. The main ( ) function can be preceded by documentation, preprocessor
statements and global declarations.
194
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.
195
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.
The main ( ) function
Each and Every C program should contain only one main ( ). The C program execution starts
with main ( ) function. No C program is executed without the main function. The main ( )
function should be written in small (lowercase) letters and it should not be terminated by
semicolon. Main ( ) executes user defined program statements, library functions and user defined
functions and all these statements should be enclosed within left and right braces.
Braces
Every C program should have a pair of curly braces ({, }). The left braces indicates the
beginning 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. These
two 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.
196
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.
User defined functions
These are subprograms, generally, a subprogram is a function and these functions are written by
the user are called user ; defined functions. These functions are performed by user specific tasks
and this also contains set of program statements. They may be written before or after a main ()
function and called within main () function. This is an optional to the programmer.
2.4 WRITING C PROGRAMS
Here is your first c program. Write carefully because C Language is a case sensitive language.
#include <stdio.h>
void main()
{
printf("Hello World\n Welcome to C Programming");
}
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
197
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.5 C TOKENS AND IDENTIFIERS
A C program consists of various tokens and a token is either a keyword, an identifier, a constant,
a string literal, or a symbol. C tokens are the basic buildings blocks in C language which are
constructed together to write a C program. Each and every smallest individual unit in a C program is
known as C tokens. C tokens are of six types. They are
printf
(
"Hello, World! \n"
)
;
Semicolons ;
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 entity.
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:
/* my first program in C */
You cannot have comments within comments and they do not occur within a string or character
literals.
Identifiers
• Identifiers are the names given to variables, classes, methods and interfaces.
• It must be a whole word and starts with either an alphabet or an underscore.
• They are case sensitive.
• No commas or blanks are allowed in it
• No special symbol other than an underscore can be used in it.
Ex.: marks gracesem1_rollno alpha
Keywords
• Keywords are words that have special meaning to the C compiler.
199
• An identifier cannot have the same spelling and case as a C keyword.
• C makes use of only 32 keywords or reserved words which combine withthe formal
syntax to the form the C programming language.
• All keywords in C are written in lower case.
• A keyword may not be used as a variable name.
int age;
There must be at least one whitespace character (usually a space) between int and age for the
compiler to be able to distinguish them. On the other hand, in the following statement:
No whitespace characters are necessary between fruit and =, or between = and apples, although
you are free to include some if you wish for readability purpose.
200
2.6 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 discusses 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.
In c, there are three types of data-primary, derived and user-defined
In C language the system has to know before-hand, the type of numbers or characters
being used in the program. These are called data types. There are many data types in C
language.
A C programmer has to use appropriate data type as per his requirement.
C language data types can be broadly classified as
a) Primary data type-int, char, float, double
b) Derived data type(secondary)- array, function, pointer, structure, union
c) User-defined data type-typedef, enum
201
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 sizes
and value ranges –
202
Long 8 bytes or (4bytes for 32 bit -9223372036854775808 to
OS) 9223372036854775807
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
Keyword char is used for declaring character type variables. For example,
203
The size of the character variable is 1 byte. Format specifier for char type data is %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:
type variable_list;
Here, type must be a valid C data type including char, int, float, double, bool, or any user-defined
object; and variable_list may consist of one or more identifier names separated by commas. Some
valid declarations are shown here −
int i, j, k;
char c, ch;
204
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 int.
You 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 or
a 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;
205
printf("value of f : %f \n", f);
return 0;
}
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'.
206
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 are
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.
207
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.
Single Character Constants
A Single Character constant represent a single character which is enclosed in a pair of quotation
symbols.
Example for character constants are
8
'5', 'x', ';', ' '
All character constants have an equivalent integer value which is called ASCII Values.
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", "!.....?"
2.9 CONSTANT DECLARATION IN C
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 days_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
readable.
The general form of a constant declaration is:
const type constant-identifier = value ;
type is the type of the constant, constant-identifier is the identifier chosen for the constant, which
must be distinct from all identifiers for variables, and value is an expression involving only
constant quantities that gives the constant its value. It is not possible to declare a constant
without giving it an initial value.
208
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. The variables and constants declared in global declaration can be accessed
by all user-defined functions and the main program. Where as the variables and constants
declared in local declaration part are local to the section.
2.11 KEYWORDS
I
dentifier, Variable, Keyword, int, float, const, extern, user defined function, char,global
declaration, local declaration,tokens
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.
209
2..13 REFERENCES
1. Programming In ANSI C by E Balagurusamy
2. The C Programming Language (Ansi C Version) by Brian W. Kernighan, Dennis M.
Ritchie
3. Expert C Programming: Deep C Secrets by Peter Van, Der Linden
4. Programming in C - Gottfried B.S., TMH
5. Programming in ANSI C - Balaguruswami, TMH
6. C The Complete Reference - H.Sohildt, TMH
7. Let us C - Y.Kanetkar, BPB Publications
8. A Structured Programming Approach using C – B.A. Forouzan& R.F. Gillberg,
THOMSON Indian Edition
9. Computer fundamentals and programming in C – PradipDey&Manas Ghosh, OXFORD
10. P. K. Sinha &PritiSinha , “Computer Fundamentals”, BPB Publications, 2007.
11. Dr. Anita Goel, Computer Fundamentals, Pearson Education, 2010.
210
UNIT-3
Structure:
3.0 Objectives
3.1 Introduction
3.2 Assignment statement
3.3 operators and their precedence rule
3.3.1 Unary operators
3.3.2 arithmetic operators
3.3.3 relational operators
3.3.4 logical operators
3.3.5 bitwise operators
3.3.6 assignment operators
3.3.7 increment and decrement operators
3.3.8 conditional operator
3.3.9 size of() operator
3.3.10 special operator
3.3.11 Expression
3.3.12 Operators precedence rule
3.4 Library functions
3.5 Type conversion in C
3.6 Summary
3.7 Keywords
3.8 Questions for self study
3.9 References
3.0 OBJECTIVES
211
Elucidate library functions
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.
3.2 ASSIGNMENT STATEMENT
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.
212
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.
213
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 puts B's value into A. This destroys A's original value
3. 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.
214
6 Conditional (ternary) Conditional operators return one value if
operators condition is true and returns another value
is condition is false.
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.
217
*, / 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);
218
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 1.The following table illustrates the relational
operators in C:
== Equal to
!= Not equal to
219
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
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 value.ie, 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,
Expression Interpretation Value
(a>b)&&(a==100) True 1
(b>a)||(a>b) True 1
!(a>b) False 0
220
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
221
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:
222
/* 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) */
223
Note:- The receiving variable(LHS) should be present in the RHS expression.
So beside = operator, +=,- =, /=, %= , *= are used and they are called shorthand operators.
operator Equation Assignment operator equation
+= i=i+1 i+=1
-= i=i-10 i-=10
*= i=i*11 i*=11
/= i=i/12 i/=12
%= i=i%5 i%=5
Program to demonstrate assignment operators:
#include <stdio.h>
/* a program demonstrates C assignment operator */
void main(){
int x = 10;
/* demonstrate = operator */
int y = x;
printf("y = %d\n",y);
/* demonstrate += operator */
y += 10;
printf("y += 10;y = %d\n",y);
/* demonstrate -= operator */
y -=5;
printf("y -=5;y = %d\n",y);
/* demonstrate *= operator */
y *=4;
printf("y *=4;y = %d\n",y);
/* demonstrate /= operator */
y /=2;
printf("y /=2;y = %d\n",y);
}
224
3.3.7 INCREMENT AND DECREMENT OPERATORS
In C, ++ and -- are called increment and decrement operators respectively. Both of these
operators are unary operators, i.e, used on single operand. ++ adds 1 to operand and -- subtracts 1
from 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.
225
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>
226
Void main( )
int a, b,c;
scanf(“%d%d”,&a,&b);
printf(“%d”, c);
227
char is: 1 bytes
float is: 4 bytes
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
Floating-point expressions: Evaluate to real numbers, like 3.141 or -0.005
String expressions: Evaluate to character strings
If more than one operator is involved in an expression then, C language has predefined
rule 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)
229
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
230
<< >> Bitwise shift left, Bitwise shift right left-to-right
|| 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
Each function here performs a specific operation. We can use this library functions to get the
pre-defined output.
231
All C standard library functions 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.
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 functions.Built 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.
232
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
233
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:
234
(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
This is done to take advantage of certain features of type hierarchies or type
representations.
It helps us to compute expressions containing variables of different data types.
3.6 SUMMARY
In this unit, you have studied the different types of operators available in C.The 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, decrement, bitwise,
logical, special operator, comma operator, library functions, math.h, string.h, implicit type
conversion, explicit type conversion
235
3.8 QUESTIONS FOR SELF STUDY
236
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
4.12 Reference
4.0 OBJECTIVES
237
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.
238
Fig 9.1: Shows Flowchart of goto statement
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;
239
}
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: 19
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.
240
Fig 9.2: Shows flow chart of If statement
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;
241
printf (“ enter a number:”\n);
scanf(“%d”,&x);
If (x>20)
Printf(“ number is greater”);
}
Output:
Enter a number:22
Number is greater
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)
242
{
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;
243
The value is less than 20
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
on 1
False
True
Condit
ion 2 False
True
Statement block2
244
Next statement
Fig 9.4 : Shows flowchart of Nesting of if statements
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.
245
If a case match is NOT found, then the default statement is executed, and the control goes out of
the switch block.
Syntax:
switch( choice )
{
case 1:
statement 1;
break;
246
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;
247
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 condition is satisfied.
While loop
Syntax:-
248
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 used.Initialy
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 will get
executed repeatedly.
Do while loop
This (do while loop) statement is also used for looping. The body of this loop may
249
contain single statement or block of statement. The syntax for writing this statement is:
Syntax:-
Do
Statement;
while(condition);
Example:
#include <stdio.h>
int main()
{
int j=0;
do
{
printf("Value of variable j is: %d\n", j);
j++;
}while (j<=3);
return 0;
}
Output:
Value of variable j is: 0
Value of variable j is: 1
Value of variable j is: 2
Value of variable j is: 3
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 thecondition
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 forfirst time. It
means do while loop always executes at least once.
250
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 –).
251
Fig 9.6: Shows flowchart of For loop
Syntax:-
for(exp1;exp2;exp3)
Statement;
}
or
Statement;
252
Example:
#include <stdio.h>
int main()
{
int i;
for (i=1; i<=3; i++)
{
printf("%d\n", i);
}
return 0;
}
Output:
1
2
3
253
Here exp1 is an initialization expression, exp2 is test expression or condition and exp3 is an
update expression. Expression 1 is executed only once when loop started and used to
initialize the loop variables. Condition expression generally uses relational and logical
operators. And updation part executed only when afterbody of the loop is executed.
Break statement(break)
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 cause immediate exit from that loop in whichit 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 ifstatement.
Example : #include <stdio.h>
int main()
{
int num =0;
while(num<=100)
{
printf("value of variable num is: %d\n", num);
if (num==2)
{
break;
}
num++;
}
printf("Out of while-loop");
return 0;
}
101
Output:
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 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.
#include <stdio.h>
int main ()
{
int a,sum = 0;
for (a = 0; a < 10; a++)
{
if ( a % 2 == 0 )
continue;
sum = sum + a;
}
printf("sum = %d",sum);
return 0;
102
}
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
4.12 REFERENCES
103
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.5 Prototype of Function
5.6 Calling a Function
5.7 Summary
5.8 Keywords
5.9 Questions for self-study
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
104
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.
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 bellow illustrate how function can be used in programming
//C Program for Addition of Two Number's using User Define Function
#include<stdio.h>
105
#include<conio.h>
float add(float,float); // function declaration
void main()
{
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();
}
// Here is the function definitation
float add(float x,float y)
{
float z;
z=x+y;
return(z);
}
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.
106
Bar Graphs – Bar Graph is used to display the category of data and it compares the
data using solid bars to represent the quantities.
Histograms – The graph that uses bars to represent the frequency of numerical data
that are organised into intervals. Since all the intervals are equal and continuous, all
the bars have the same width.
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 again.
107
Frequency Table – The table shows the number of pieces of data that falls within the
given interval.
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.
Stem and Leaf Plot – In the stem and leaf plot, the data are organised 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.
108
Box and Whisker Plot – The plot diagram summarises the data by dividing into four
parts. Box and whisker show the range (spread) and the middle ( median) of the data.
There are certain rules to effectively present the information in the graphical representation.
They are:
Suitable Title: Make sure that the appropriate title is given to the graph which
indicates the subject of the presentation.
Measurement Unit: Mention the measurement unit in the graph.
Proper Scale: To represent the data in an accurate manner, choose a proper scale.
Index: Index the appropriate colours, shades, lines, design in the graphs for better
understanding.
Data Sources: Include the source of information wherever it is necessary at the
bottom of the graph.
Keep it Simple: Construct a graph in an easy way that everyone can understand.
Neat: Choose the correct size, fonts, colours etc in such a way that the graph should
be a visual aid for the presentation of information.
109
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.
o Histogram
110
o Smoothed frequency graph
o Pie diagram
o Cumulative or ogive frequency graph
o Frequency Polygon
Here are the steps to follow to find the frequency distribution of a frequency polygon and it is
represented in a graphical way.
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.
111
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:
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 C standard library functions 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.
112
Some of the header file functions are as follows
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 functions.Built functions in stdio.h
For example:
main()
The execution of every C program starts from this main.
printf()
prinf() is 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(){
113
................
................
}
int main(){
...........
...........
function_name();
...........
...........
}
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.
114
#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 call
printf("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.
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.
115
5.6 Calling a Function
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 to
define 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 to
a 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 with
arguments, but omitting for the moment to declare the function fully.
#include <stdio.h>
#include <stdlib.h>
main(){
void pmax(); /* declaration */
int i,j;
for(i = -10; i <= 10; i++){
for(j = -10; j <= 10; j++){
pmax(i,j);
}
}
exit(EXIT_SUCCESS);
}
116
/*
* Function pmax.
* Returns: void
* Prints larger of its two arguments.
*/
void
pmax(int a1, int a2){ /* definition */
int biggest;
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
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
117
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:
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.
#include <stdio.h>
main()
{
int x=3;
printf(“\n x=%d(from main, before calling the
function”),x);
change(x);
printf(“\n\nx=%d(from main, after calling the
function)”,x);
}
change(x)
int x;
{
x=x+3;
printf(“\nx=%d(from the function, after being
modified)”,x);
return;
}
118
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 main
from 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.
#include <stdio.h>
int non_space(void) {
int c;
while ( (c=getchar ())=='\t' || c== '\n' || c==' ')
; /* empty statement */
return (c);
119
}
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
auto keyword. Otherwise, a nested function has internal linkage.
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.
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.
120
When a program begins running, the system calls the function main, which marks the entry
point of the program. By default, main has the storage class extern. Every program must have
one function named main, and the following constraints apply:
Although any name can be given to these parameters, they are usually referred to
as 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 just say that when you need it, you really do need it, and since it doesn't cost much to
put into a language, as you would expect, C supports recursion.
121
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 to
find 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 declared
in stdio.h.
122
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 */
} else{
printf("result is %d\n", val);
}
123
}
exit(EXIT_SUCCESS);
}
int
expr(void){
int val, ch_in;
val = mul_exp();
for(;;){
switch(ch_in = getchar()){
default:
ungetc(ch_in,stdin);
return(val);
case '+':
val = val + mul_exp();
break;
case '-':
val = val - mul_exp();
break;
}
}
}
int
mul_exp(void){
int val, ch_in;
val = unary_exp();
for(;;){
switch(ch_in = getchar()){
default:
ungetc(ch_in, stdin);
return(val);
case '*':
val = val * unary_exp();
break;
124
case '/':
val = val / unary_exp();
break;
case '%':
val = val % unary_exp();
break;
}
}
}
int
unary_exp(void){
int val, ch_in;
switch(ch_in = getchar()){
default:
ungetc(ch_in, stdin);
val = primary();
break;
case '+':
val = unary_exp();
break;
case '-':
val = -unary_exp();
break;
}
return(val);
}
int
primary(void){
int val, ch_in;
ch_in = getchar();
if(ch_in >= '0' && ch_in <= '9'){
val = ch_in - '0';
goto out;
125
}
if(ch_in == '('){
val = expr();
getchar(); /* skip closing ')' */
goto out;
}
printf("error: primary read %d\n", ch_in);
exit(EXIT_FAILURE);
out:
return(val);
}
automatic
external
static
register
126
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.
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
127
library function
used defined function
5.10 Reference
1. Programming In ANSI C by E Balagurusamy
2. The C Programming Language (Ansi C Version) by Brian W. Kernighan, Dennis M.
Ritchie
3. Expert C Programming: Deep C Secrets by Peter Van, Der Linden
128
Unit - 6
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 Pointers & Array
6.8 Summary
6.9 Key words
6.10 Questions
6.11 References
6.0 Objectives
129
Describe the functionality of pointer
List out various operation on pointers
Explain the arithmetic operation performed on pointers
In its simplest terms, an array can be defined as a formation of digits, images, or objects
arranged in rows and columns in accordance with their types. Comprehending the concept
of array facilitates your tedious work and allows you to make it concise as arrays illustrate
numerous data elements of similar type using a sole name.
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.
130
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.
Example:
int *ptr;
float *string;
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
131
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.
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
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)
132
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;
{
*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
133
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>
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
134
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:
The dereference operator can be applied as many times as necessary to access data pointed at
indirectly via multiple pointers. For example, the statement:
135
A = PTR_NEW(PTR_NEW(47))
PRINT, **A
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, *struct.pointer
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.
136
PRINT, *45
IDL prints:
For example:
The EQ and NE operators allow you to compare pointers to see if they point at the same heap
variable. For example:
137
IDL prints:
A EQ B: 1
A NE B: 0
A EQ C: 0
C EQ NULL: 1
C NE NULL: 0
If you're going to master C, you need to understand pointer arithmetic, and in particular, the
relationship between arrays and pointers.
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.
In general, this is one of the pitfalls of C. Arbitrary pointer casting allows you to point
anywhere in memory.Unfortunately, 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.
138
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.
int arr[ 10 ] ;
You might think from the above statement that arr is of type int. However, arr, by itself,
without any index subscripting, can be assigned to an integer pointer.
In particular:
arr[ i ] == * ( arr + i )
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 ].
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?
139
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 arr.The idea is to have arr + i point
to i elements after arr regardless of what type of element the array holds.Suppose 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).
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 size.You can find out the data type's size with
the sizeof() operator.
140
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:
int arr[ 10 ] ;
arr is a constant. It is defined to be the address, & arr[ 0 ].
int arr[ 10 ] ;
int arr[ 10 ] ;
int * ptr ;
141
// code here
}
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 ;
As it turns out, we can even point way past the end of the array.
int arr[ 10 ];
int * p1, * p2;
142
If you try to compute the array's size using sizeof, you just get 4.
int arr2[ 10 ] ;
// 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.
int arr[ 10 ][ 12 ] ;
What type is arr? You may have been told that it's int **, but that's incorrect. Two
dimensional arrays (as declared above) are contiguous in memory. If you create an array of
pointers to dynamically allocated arrays, such as:
int * arr[ 10 ] ;
then, arr has type int ** (or at least has a type compatible with int **).
The type is rather complicated, and is due to the fact that arr[ 0 ] = & arr[ 0 ][ 0 ], arr[ 1 ] = &
arr[ 1 ][ 0 ], and in general, arr[ i ] = & arr[ i ][ 0 ].
Pointer arithmetic says that arr + i gives you & arr[ i ], yet this skips an entire row of 12
elements, i.e., skips 48 bytes times i. Thus, if arr is address 1000 then arr + 2 is address 1096.
143
If the array's type were truly int **, pointer arithmetic would say the address is 1008ten, so
that doesn't work.
int (*ptr)[ 10 ] ;
Which is a pointer to an array of 10 elements? Thus, when you do pointer arithmetic, it can
compute the size of the array and handle it correctly. The parentheses are NOT optional
above. Without the parentheses, ptr becomes an array of 10 pointers, not a pointer to an array
of 10 int.
If you have a conventional two dimensional array, and you want to compute the address
for arr[ row ][ col ] and you have ROWS rows (where ROWS is some constant)
and COLS columns, then the formula for the address in memory is:
addr( & arr[ row ][ col ] ) = addr( arr ) + [ sizeof( int ) * COLS * row ]+ [ sizeof( int ) * col ]
Two dimensional arrays are stored in row major order, that is, row by row. Each row
contains COLS elements, which is why you see COLS in the formula. In fact, you don't
see ROWS.
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.
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.
144
The following, however, is NOT valid in C:
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 ;
p2 and p1 need not point to valid elements in an array. The formula above still works even
when p2 and p1 contain invalid addresses (because they contain some address).
145
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 visualized
with a suitable examples. In subsequent stages we have discussed about the role of & and *
operators. In the later stages we had list out various arithmetic operations which can be
performed using pointer. In the last section of the unit we have seen how exactly arrays can
be handled using pointer.
6.8 Keywords
Pointer, & and * operator, Sizeof(), Null
6.10 Reference
1. "Common Pointer Pitfalls" by Dave Marshall
2. C Programming: A Modern Approach by K.N. King
3. C Programming in 12 Easy Lessons by Greg Perry
4. C for Dummies Vol. II by Dan Gookin
146
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
147
At the end of this unit, you will be able to
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 is declared in C in similar manner as arrays. Only difference is that, strings are
of char type.
char s[5];
148
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[20];
printf("Enter name: ");
scanf("%s",name);
printf("Your name is %s.",name);
return 0;
}
Output
Enter name: Dennis Ritchie
149
Your name is Dennis.
Here, program will ignore Ritchie because, when the scanf() function takes only string before
the white space.
#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.
#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:
150
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.
The above statement prints the prompt in the quotes and moves the cursor to the next line.
151
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.
printf("%d\n", val1);
printf("%d\n", val2);
152
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.
153
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.
printf("Name: ");
puts(name); //Function to display string.
154
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, gets(), puts(), string.h
7.9 Questions
1. Explain about string data type which is supported in C?
2. How can an arithmetic operation can be performed on string?
3. Write a C program to accept two strings and concatenate them?
4. Write a C program to reverse a string?
7.10 Reference
155
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
156
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 will be collection of this information under single name because all these
information are related to person.
Structure Definition in C
Syntax of structure
struct structure_name
{
data_type member1;
data_type member2;
.
.
157
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
{
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.
158
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)
Suppose, if we want to access salary for variable p2. Then, it can be accessed as: p2.salary
#include <stdio.h>
struct Distance{
int feet;
float inch;
}d1,d2,sum;
int main(){
printf("1st distance\n");
printf("Enter feet: ");
scanf("%d",&d1.feet); //input of feet structure for d1
printf("Enter inch: ");
scanf("%f",&d1.inch); //input of inch structure for d1
printf("2nd distance\n");
printf("Enter feet: ");
scanf("%d",&d2.feet); //input of feet for structure variable d2
printf("Enter inch: ");
scanf("%f",&d2.inch); //input of inch for structure variable d2
sum.feet=d1.feet+d2.feet;
sum.inch=d1.inch+d2.inch;
if (sum.inch>12){ //If inch is greater than 12, changing it to feet.
++sum.feet;
sum.inch=sum.inch-12;
}
printf("Sum of distances=%d\'-%.1f\"",sum.feet,sum.inch); //printing sum of distance d1 and d2
return 0;
}
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.
Programmers are generally use typedef while using structure in C language. For example:
159
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.
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
member.Structures 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
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.
160
8.5 Structure and function
For example consider the C program to create a structure student, containing name and roll.
Ask user the name and roll of a student in main function. Pass this structure to a function and
display the information in that function.
#include <stdio.h>
struct student{
char name[50];
int roll;
};
void Display(struct student stu);
/*function prototype should be below to the structure declaration
otherwise compiler shows error */
int main(){
struct student s1;
1 printf("Enter student's name: ");
scanf("%s",&s1.name);
printf("Enter roll number:");
scanf("%d",&s1.roll);
Display(s1); //passing structure variable s1 as argument
return 0;
}
void Display(struct student stu){
printf("Output\nName: %s",stu.name);
printf("\nRoll: %d",stu.roll);
}
Output
Enter student's name: Kevin Amla
Enter roll number: 149
Output
Name: Kevin Amla
Roll: 149
161
Passing structure by reference
The address location of structure variable is passed to function while passing it by reference.
If structure is passed by reference, change made in structure variable in function definition
reflects in original structure variable in the calling function.
Write a C program to add two distances (feet-inch system) entered by user. To solve this
program, make a structure. Pass two structure variable (containing distance in feet and inch)
to add function by reference and display the result in main function without returning it.
#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",&dist1.feet);
printf("Enter inch: ");
scanf("%f",&dist1.inch);
printf("Second distance\n");
printf("Enter feet: ");
scanf("%d",&dist2.feet);
printf("Enter inch: ");
scanf("%f",&dist2.inch);
Add(dist1, dist2, &dist3);
162
d3->inch-=12;
++d3->feet;
}
}
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.
163
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,
Passing the members of the structures as an argument.
Passing the entire structure as an argument.
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;
};
164
union car c1, c2, *c3;
In both cases union variables c1, c2 and union pointer variable c3 of type union car is
created.
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
c1.price. If you want to access price for union pointer variable c3, it can be accessed
as (*c3).price or as c3->price.
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
165
There is difference of memory allocation between union and structure as suggested in above
example. The amount of memory required to store a structure variables is the sum of memory
size of all members.
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",&u.name);
printf("Enter salary: \n");
scanf("%f",&u.salary);
printf("Displaying\nName :%s\n",u.name);
printf("Salary: %.1f",u.salary);
return 0;
}
Output
Enter name
Hillary
Enter salary
1234.23
Displaying
Name: f%Bary
Salary: 1234.2
166
Note: You may get different garbage value of name.
When code in line no. 9 is executed, Hillary will be stored in u.name and other members of
union will contain garbage value. When code all will executed, 1234.23 will be stored in
u.salary and other members will contain garbage value. Thus in output, salary is printed
accurately but, name displays some random string.
167
int age;
}
struct info std[100];
int I,n;
printf(“Enter the number of students”);
scanf(“%d”,&n);
printf(“ Enter Id_no,name address combination age\m”);
for(I=0;I < n;I++)
scanf(%d%s%s%s
%d”,&std[I].id_no,std[I].name,std[I].address,std[I].combinatio
n,&std[I].age);
printf(“\n Student information”);
for (I=0;I< n;I++)
printf(“%d%s%s%s%d\n”,”,std[I].id_no,std[I].name,std[I].address,std[I].combination,std[I].age);
}
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;
168
q = p;
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 pass a pointer to that structure. This is just like passing a pointer to an int type argument
whose value we wish to change.
If 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 it.
When 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;
169
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));
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
170
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 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.
171
/* 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 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.
172
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 (account.balance) (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, 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 etc.
173
Like 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.
8.14 Summary
At the end this unit we have learnt the concepts about structure and unions. We have
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
174
2. How can structure be treated as a function argument?
3. Explain the concept of union defined functions?
4. Do survey and prepare report on how exactly the structure is different from class in
object orient programming?
8.17 Reference
1. C Programming: A Modern Approach by K.N. King
2. C Programming in 12 Easy Lessons by Greg Perry
3. C for Dummies Vol. II by Dan Gookin
175
UNIT 9: INPUT AND OUTPUT
Structure:
9.0 Objectives
9.1 Introduction
9.2 Input and output
9.3 The printf() function
9.4 The scanf() function
9.5 Getchar() and Putchar() function
9.6 Gets() and puts() function
9.7 File handling in C
9.8 Summary
9.9 Keywords
9.10 Questions
9.11 References
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
176
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 program
reading 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:
177
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.
178
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
#include <stdio.h>
int main() {
// using printf()
printf("Welcome to Studytonight");
return 0;
Copy
Welcome to Studytonight
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>
179
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:
180
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;
}
Output:
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
181
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
182
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>
183
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.
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);
184
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
185
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.
186
int getchar(void);
You can use this method in a loop if you want to read more than one character.
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:
187
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:
188
Enter a string: Studytonight
Studytonight
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
189
The string is: abcdefghij
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.
190
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.
191
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()
192
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
193
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
r+ up 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
a+ 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 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”.
194
// C Program to illustrate file opening
#include <stdio.h>
#include <stdlib.h>
int main()
{
// file pointer variable to store the value returned by
// fopen
FILE* fptr;
// opening the file in read mode
fptr = fopen("filename.txt", "r");
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;
195
Example of Opening a File
Output
The file is created Successfully.
Function Description
196
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;
char 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:
Function Description
197
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 ;
fputc("a", 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(“fileName.txt”, “w”);
fclose(fptr);
198
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
9.10 QUESTIONS
9.11 REFERENCES
199
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.
200
10.1 INTRODUCTION
To make the coding of a program more intelligible, it is sometimes useful to replace integer
the enum keyword, and is an ordered collection of names that represent integer values.
Unless otherwise specified, the first name in the collection represents 0, the second name
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:
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
201
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, the error message will not be displayed.
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;
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.
202
Let's understand through a simple example.
#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
Value of i is :10
Value 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:
203
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;
int main()
204
{
stud s1;
printf("Enter the details of student s1: ");
printf("\nEnter the name of the student:");
scanf("%s",&s1.name);
printf("\nEnter the age of student:");
scanf("%d",&s1.age);
printf("\n Name of the student is : %s", s1.name);
printf("\n Age of the student is : %d", s1.age);
return 0;
}
Output
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
variable of type int* by simply using the 'ptr' variable as shown in the below statement:
205
ptr p1, p2 ;
10.3 Enumeration in C
Syntax :
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 :
#include<stdio.h>
int main()
{
int i;
enum day {MON,TUE,WED,THU,FRI,SAT,SUN};
for(i=MON;i<=SUN;i++) {
printf("%d ",i);
}
return 0;
}
Output
0123456
206
Points to remember :
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, TUE
gets 1, and so on.
#include<stdio.h>
int main()
{
int i;
enum day {MON,TUE,WED,THU,FRI,SAT,SUN};
for(i=MON;i<=SUN;i++) {
printf("%d ",i);
}
return 0;
}
Output
207
0123456
We can assign values to some name in any order. All unassigned names get value as
value of previous name plus one.
#include<stdio.h>
int main()
{
enum day {MON = 1,TUE,WED,THU = 7,FRI,SAT,SUN};
printf("%d %d %d %d %d %d %d ",MON,TUE,WED,THU,FRI,SAT,SUN);
return 0;
}
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.
208
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:
209
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:
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.
210
cur_cont = cont1;
printf("Value of hearts is = %d \n", cur_cont);
return 0;
}
Output:
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.
211
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 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
};
212
int main() {
int myExample = ROTATE | SAVE;
printf("%d", myExample);
return 0;
}
Output:
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:
213
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:
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:
214
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
215
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.
10.6 KEYWORDS
10.7 QUESTIONS
10.8 REFERENCES
Structure:
11.0 Objectives
11.1 Introduction
11.2 Bitwise operation
11.3 Bitwise operators
11.4 Summary
216
11.5 Keywords
11.6 Questions
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).
217
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 one
of 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.
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
218
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.
219
Arithmetic logic unit, part of a computer CPU, is where bitwise operators used to perform
mathematical operations.
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.
220
Operator Name Description Application
& 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.
221
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.
222
Operator Name Type Action
223
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.
224
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.
225
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.
226
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
227
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, bitwise NOT, bitwise left shift
and bitwise right shift.
11.6 QUESTIONS
11.7 REFERENCES
228
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
229
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, free). 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.
230
Now, Let us see the definition, syntax and some examples of each library functions below.
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 functions
like malloc(), calloc(), realloc(), and free() to allocate and deallocate a memory block during
run-time.
It is considered as a very important topic because almost every Data Structure (such as
Linked Lists, Stack, Queue, Trees, etc.) is associated with the concept of Dynamic Memory
Allocation in C.
To 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 one
is 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
231
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 Allocation.
Now, 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 We can allocate and deallocate a memory block
during run-time. during run-time.
It doesn't provide reusability of memory, while the It provides reusability of memory, while the
program is running. So, it is less efficient. program is running. So, it is more efficient.
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 program.
There are further four components in which our system's memory is divided:
232
1. Stack Segment (Static Memory)
2. Global Variables Segment (Static Memory)
3. Instructions / Text Segment (Static Memory)
4. Heap Segment (Dynamic Memory)
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
application.
o We can't allocate or deallocate memory during execution.
Heap
233
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;
}
234
}
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.
235
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.
236
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 :
237
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.
238
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));
}
}
239
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 example
output.
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:
240
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);
}
// deallocating memory pointed by ptr
241
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);
242
// 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
Explanation :
243
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() function.
Now, 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().
244
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 allocated
using 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.
Examples of realloc()
C Program :
245
// C Program to reallocate memory blocks during run-time
#include <stdio.h>
#include <stdlib.h>
int main() {
int n;
scanf("%d", &n);
printf("\n");
246
return 0;
}
Input
5
0 1 650005713 46458 12462928
Output :
Explanation :
#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 {
247
*ptr = 7;
printf("%d\n", *ptr);
printf("%d\n", *ptr);
return 0;
}
Output:
7
15078952
Memory freed using realloc()!
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.
248
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));
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.7SUMMARY
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
Dynamic memory allocation, Static memory allocation, malloc(), calloc(), free() and
realloc().
12.9 QUESTIONS
249
5. Describe realloc() method().
12.10 REFERENCES
250
UNIT 13
LINKED LISTS
Structure:
13.0 Objectives
13.1 Introduction
13.5 Summary
13.6 Keywords
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
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 structure.For
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 address
of 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.
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):
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.
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;
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);
}
}
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.
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.
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;
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;
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.
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.
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 :
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.
Advantages of Linked Lists
● They are a dynamic in nature which allocates the memory when required.
● Insertion and deletion operations can be easily implemented.
● Size of linked list can grow or shrink in size during the execution of a program.
● In Linked Lists we don't need to know the size in advance
● Stacks and queues can be easily implemented using linked list.
Applications of Linked Lists
● Linked lists are used to implement several other common abstract data types (data structures),
including lists , stacks , queues , associative arrays , and S-expressions .
● Linked lists let you insert elements at the beginning and end of the list.
13.6 KEYWORDS
Linked list, singly linked list, doubly linked list, circular linked list, insertion, deletion,creation,
traverse
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.
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
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.
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 datastracture 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) lists.
As 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.
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.
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.
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 full.IF
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.
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.
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 deletion.
Like 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.
QUEUE Representation:
Let us consider a queue, which can hold maximum of five elements. Initially the queue is empty.
1. Insert 11.
2. Insert 22
3. insert 33
4. Delete 11
5. Delete 22
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.
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:");
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:
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 ");
}
}
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;
}
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
# include <conio.h>
# include <stdlib.h>
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;
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()
{
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
# 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..");
}
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;
}
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 list.
The 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. Where as queue has two pointers front and rear.
In stack, insertion and deletion operations are done from only one end. In queue , insertion is
from rear end and deletion is from front end.
During insertion operation, we check for overflow condition and during deletion operation, the
data structures are checked for underflow condition.
14.7 KEYWORDS
14.9 REFERENCES
RECURSION
Structure:
15.0 Objectives
15.1 Introduction
15.2 Recursion
15.3 Summary
15.4 Keywords
15.6 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.
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 */
… .. …
}
int main()
{
… .. …
recurse();
… .. …
}
int factorial(int x)
if(x <= 1)
return 1;
int main()
int x = 12;
return 0;
OUTPUT:
The factorial of the number 12 is equal to 479001600
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
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;
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
15.3 SUMMARY
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.
When writing recursive functions, you must have a exit 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.
15.4 KEYWORDS
Recursion, exit condition
1. Define recursion.
15.6 REFERENCES
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.
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
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;
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).
Difference between Structure and Union
int main()
{
void (*fun_ptr)(int) = fun; // & removed
fun_ptr(10); // * removed
return 0;
}
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 ("unexist.txt", "rb");
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);
}
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...
Program Exit Status
It is a common practice to exit with a value of EXIT_SUCCESS in case of programming is
coming out after a successful operation. Here, EXIT_SUCCESS is a macro and it is defined as
0.If you have an error condition in your program and you are coming out then you should exit
with a status EXIT_FAILURE which is defined as -1.
So let's write above program as follows:
#include <stdio.h>
#include <stdlib.h>
m ain()
{
int dividend = 20;
int divisor = 5;
int quotient;
if( divisor == 0){
fprintf(stderr, "Division by zero! Exiting...\n");
exit(EXIT_FAILURE);
}
quotient = dividend / divisor;
fprintf(stderr, "Value of quotient : %d\n", quotient );
exit(EXIT_SUCCESS);
}
When the above code is compiled and executed, it produces the following result:
Value ofquotient : 4
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. The union stores a collection of items of
diverse data kinds in the same memory region. A user can create a union with numerous
members, but only one member can hold a value at any given moment. The total storage space
required by the union’s biggest data member is equal to the storage space allotted for the union
variable.
16.7 KEYWORDS
Structure, union, pointer, function pointer, error handling,struct,union
16.8 QUESTIONS FOR SELF STUDY
1. Explain structure with its syntax.
16.8 REFERENCES