0% found this document useful (0 votes)
94 views129 pages

Programming in C&DS TextBOOK 1

This document provides an introduction to the C programming language. It discusses that C was created at Bell Labs in 1972 and was designed for writing operating systems. C is still widely used today for developing systems software like operating systems and device drivers due to its high performance. The document outlines that C programs can be understood similarly to how English is learned, by first understanding basic elements like characters, variables, and keywords, and then combining them to write instructions and programs. It also defines high-level and low-level programming languages and describes compilers and interpreters.

Uploaded by

mahender5222792
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
0% found this document useful (0 votes)
94 views129 pages

Programming in C&DS TextBOOK 1

This document provides an introduction to the C programming language. It discusses that C was created at Bell Labs in 1972 and was designed for writing operating systems. C is still widely used today for developing systems software like operating systems and device drivers due to its high performance. The document outlines that C programs can be understood similarly to how English is learned, by first understanding basic elements like characters, variables, and keywords, and then combining them to write instructions and programs. It also defines high-level and low-level programming languages and describes compilers and interpreters.

Uploaded by

mahender5222792
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 129

Instructional Material

Post Graduate Diploma in Computer


Applications
Semester - I
Programming In C & Data Structures
Paper - 1

Editor
Prof. K. Shyamala
Professor & Head
Department of Computer Science Engineering,
University College of Engineering, OU, Hyderabad
.
Course Writers
Mr. M. Narendar Reddy, M.C.A., M.Tech.,
Asst.Professor,
Department of Computer Science Engineering,
University College of Engineering, OU, Hyderabad

Mrs. V. Sukanya, M.Tech., IIIT


Asst.Professor,
Department of Computer Science Engineering,
University College of Engineering, OU, Hyderabad

Director
Prof. Chintha Ganesh

Prof. G. Ram Reddy Centre for Distance Education


Osmania University, Hyderabad – 500 007
2018-2019
101 IT PROGRAMMING IN C AND DATA STRUCTURES
Instruction : (4L) hrs per week Duration of SEE : 3 hours
CIE : 30 marks SEE : 70 marks

UNIT I
Introduction to C Language – Background, C identifiers, Data Types, Operators, Variables,
Constants, Input / Output, Expressions, C Programs, Precedence and Associativity,
Evaluating Expressions, Types of Conversions, Statements, Bitwise Operators.
Selection : Logical Data and Operators, if-else, switch Statements, Standard Functions.
Repetitions : Loops, while, for, do-while statements, Loop examples, Break, Continue, go to.

UNIT II
Arrays – Concepts, Using Arrays in C, Inter-Function Communication, Array Applications,
Two-Dimensional Arrays, Multidimensional Arrays, Linear and Binary Search, Selection,
Bubble, Insertion Sorts.
Functions : Function Basics, User Defined Functions, Inter Function Communication,
Standard Functions, Scope, Storage Classes-Auto, Register, Static, Extern, Scope Rules, and
Type Qualifiers.
Recursion – Recursive Functions, Terminating Condition, Preprocessor Commands.

UNIT III
Pointers – Introduction, Pointers to Pointers, Compatibility, L value and R value, Arrays and
Pointers, Pointer Arithmetic and Arrays.
Call-by-reference : Passing Arrays to a Function, Dynamic Memory Allocation: Memory
Allocation Functions, Arrays of Pointers.
Strings – Concepts, String input/Output Functions, Arrays of Strings, String Manipulation
Functions, The Type Definition (type def), Enumerated Types.

UNIT IV
Structure : Definition and Initialization of Structures, Accessing Structures, Nested
Structures, Arrays of Structures, Structures and Functions, Pointers to Structures, Self
Referential Structures and Unions.
Input and Ouput :Files, Streams, Standard Library Input Output Functions, Character Input
Output Functions.

UNIT V
Data Structures – Introduction to Data Structures, abstract data types, Linear List – singly
linked list implementation, insertion, deletion and searching operations on linear list, Stacks-
Operations, array and linked representations of stacks, stack application-infix to postfix
conversion, postfix expression evaluation, recursion implementation, Queues-operations,
array and linked representations.
Suggested Reading :
1. B.A.Forouzan and R.F. Gilberg, C Programming and Data Structures, 3rd Edition,
Cengage Learning, 2007.
2. Kernighan B W and Ritchie DM, The C Programming Language, 2nd Edition,
Prentice Hall of India, 2006.

i
PROGRAMMING IN C AND DATA STRUCTURES

TABLE OF CONTENTS

UNIT I Page No.

1.1 INTRODUCTION TO C LANGUAGE 1

1.2 C CHARACTER SET 2

1.3 C IDENTIFIERS AND KEYWORDS 3

1.4 C DATA TYPES 4

1.5 OPERATORS 6
1.6 C VARIABLES 17
1.7 C PROGRAMMING ENVIRONMENT 24

1.8 PRECEDENCE AND ASSOCIATIVITY OF OPERATORS 26

1.9 SELECTION 28

1.10 REPETITION 32

UNIT – II

2.1 ARRAYS 40
2.2 FUNCTIONS 43

2.3 RECURSION 50

2.4 PREPROCESSOR COMMANDS 52

UNIT - III

3.1 POINTERS 58

3.2 STRINGS 72

3.3 STRING MANIPULATION FUNCTIONS 74

UNIT- IV

4.1 STRUCTURES 78

4.2 NESTED STRUCTURES 79

ii
4.3 ARRAY OF STRUCTURES 80

4.4 STRUCTURES AND FUNCTIONS 80

4.5 POINTERS TO STRUCTURES 83

4.6 SELF REFERENTIAL STRUCTURES 84

4.7 UNIONS 84

4.8 STANDARD LIBRARY INPUT OUTPUT FUNCTIONS 89

4.9 CHARACTER INPUT OUTPUT FUNCTIONS 96

UNIT-V

5.1 INTRODUCTION TO DATA STRUCTURES 98

5.2 LINEAR LIST 99

5.2.1 SINGLY LINKED LIST IMPLEMENTATION 99

5.2.2 SEARCHING OPERATIONS ON LINEAR LIST 103

5.3 STACKS 104

5.4 ARRAY AND LINKED REPRESENTATIONS OF STACKS 104

5.5 STACK APPLICATION 107

5.6 QUEUES 115

iii
UNIT - I
PROGRAMMING IN C AND DATA STRUCTURES

UNIT-I

1.1 INTRODUCTION TO C LANGUAGE

C is a programming language developed at AT & T’s Bell Laboratories of USA in 1972.


It was designed and written by a man named Dennis Ritchie. In the late seventies C began
to replace the more familiar languages of that time like PL/I, ALGOL, etc ANSI C
standard emerged in the early 1980s and was initially designed for programming UNIX
operating system. Later, the software tool as well as the C compiler is written in C.
Major parts of popular operating systems like Windows, UNIX, Linux is still written in
C. This is because even today when it comes to performance (speed of execution) C
Language exceeds the performance compared to all existing languages. Moreover, if one
is to extend the operating system to work with new devices one needs to write device
driver programs. These programs are exclusively written in C. C language is popular
because it is reliable, simple and easy to use. “C has been already superceded by
languages like C++, C# and Java.
There is a close analogy between learning English language and learning C language. The
classical method of learning English is to first learn the alphabets used in the language,
then learn to combine these alphabets to form words, which in turn are combined to form
sentences and sentences are combined to form paragraphs. Learning C is similar and
easier. Instead of straight-away learning how to write programs, we must first know what
alphabets, numbers and special symbols are used in C, then how using them constants,
variables and keywords are constructed, and finally how are these combined to form an
instruction. A group of instructions would be combined later on to form a program.

A computer program is a set of the instructions necessary to solve a specific problem. An


approach or procedure to solve the problem is known as an algorithm. Programming
languages can written as Low level language or as High level language

Low level language:

The low level languages are machine level and assembly level language. In machine level
language, computer only understand digital numbers i.e. in the form of 0 and 1. So,
instruction given to the computer is in the form binary digit, which is difficult to implement
instruction in binary code. This type of program is not portable, difficult to maintain and also
error prone. The assembly language is modified version of machine level language, where
instructions are given in English like word as ADD, SUM, MOV etc. It is easy to write and
understand but not understand by the machine. Assembler is a program used to translate the
assembly language program into low level language. In the assembly level language, the data

1|P a g e
is stored in the computer register, which varies for different computer. Hence it is not
portable.

High level language: These languages are machine independent, means it is portable. The
languages in this category C, C++, C#, JAVA, Pascal, COBOL, Fortran etc. A translator is
software which is used to translate high level language as well as low level language in to
machine level language. Three types of translators are Compiler, Interpreter and
Assembler.

Compiler and interpreter are used to convert the high level language into machine level
language. The program written in high level language is known as source program and the
corresponding machine level language program is called as object program. Both compiler
and interpreter perform the same task but there working is different. Compiler read the
program at-a-time and searches the error and lists them. If the program is error free then it is
converted into object program. When program size is large then compiler is preferred.
Whereas interpreter read only one line of the source code and convert it to object code

C is a general-purpose, structured programming language. It consist of terms that resemble


algebraic expressions, augmented by certain English keywords such as if, else, for, do and
while. C language is used for systems programming (e.g., for writing operating systems) as
well as for applications programming (e.g., for writing a program to solve a complicated
system of mathematical equations, or for writing a program to bill customers).

1.2 C CHARACTER SET

C uses the uppercase letters A to Z, the lowercase letters a to z, the digits 0 to 9, and certain
special characters as building blocks to form basic program elements (e.g., constants,
variables, operators, expressions, etc.). The special characters are listed below.

+ - * / % & # ?

^ || \ | < > ( )

! ~ (blank space)

Most versions of the language also allow certain other characters, such as @ and $, to be
included within strings and comments.

C uses certain combinations of these characters, such as \b, \n and \t to represent special
conditions such as backspace, newline and horizontal tab, respectively. These character
combinations are known as escape sequences. Each escape sequence represents a single
character, even though it is written as two or more characters.

2|P a g e
1.3 C IDENTIFIERS AND KEYWORDS

Identifiers are names that are given to various program elements, such as variables,
functions and arrays. Identifiers consist of letters and digits, in any order, except that the first
character must be a letter. Both upper and lowercase letters are permitted, though common
usage favors the use of lowercase letters. Upper and lowercase letters are not
interchangeable (i.e., an uppercase letter is not equivalent to the corresponding lowercase
letter.) The underscore character ( - ) can also be included, and is considered to be a letter.
An underscore is often used in the middle of an identifier.

EXAMPLE 1:

The following names are valid identifiers.

X Y12 SuM_1 temp_1

names area t_a1 TABLE

The following names are not valid identifiers for the reasons stated.

4th The first character must be a letter.

x I' Illegal characters ('I).

order-no Illegal character (-).

error flag Illegal character (blank space).

There are certain reserved words, called keywords, that have standard, predefined meanings
in C. These keywords can be used only for their intended purpose; they cannot be used as
programmer-defined identifiers. The standard keywords are:

auto break case char const


continue do default double else
enum extern float for goto
if int long register return
short signed sizeof static struct
switch typedef union unsigned volatile
void while

3|P a g e
1.4 C DATA TYPES

C language data types are as follows :

1. Primary data type


2. Derived data type
3. User defined data type

Primary data types:

Primitive Data types in C:

DATA RANGE OF
TYPE VALUES

1. Integer int -128 to 127

2. Character char -32768 to +32767

3. Floating Point float 3.4 e-38 to 3.4 e+38

4. Double precision floating double 1.7 e-308 to 1.7 e+308


point

5. Void void ----

Integer Type:

Integers are whole numbers with a machine dependent range of values. C language has three
classes of integer storage, namely, short int, int and long int. All of these data types have
signed and unsigned forms. A short int requires half the space than normal integer values.
Unsigned numbers are always positive and consume all the bits for the magnitude of the
number. The long and unsigned integers are used to declare a long range of values.

Floating Point Type:

Floating point number represents a real number with 6 digits precision. Floating point
numbers are denoted by the keyword float. When the accuracy of the floating point number is
insufficient, the double data type can be used to define the number. The double is same as
float but with longer precision. To extend the precision further we can use long double which
consumes 80 bits of memory space.

4|P a g e
Void Type:

Using void data type, we can specify the type of a function. It is a good practice to avoid
functions that does not return any values to the calling function.

Character Type:

A single character can be defined as a character type of data. Characters are usually stored in
8 bits of internal storage. The qualifier signed or unsigned can be explicitly applied to char.
While unsigned characters have values between 0 and 255, signed characters have values
from –128 to 127.

Size and Range of Data Types on 16-bit machine:

TYPE SIZE Range


(Bits)

Char or 8 -128 to 127


Signed Char

Unsigned 8 0 to 255
Char

Int or Signed 16 -32768 to 32767


int

Unsigned int 16 0 to 65535

Short int or 8 -128 to 127


Signed short
int

Unsigned 8 0 to 255
short int

Long int or 32 -2147483648 to 2147483647


signed long
int

Unsigned 32 0 to 4294967295

5|P a g e
long int

Float 32 3.4 e-38 to 3.4 e+38

Double 64 1.7e-308 to 1.7e+308

Long Double 80 3.4 e-4932 to 3.4 e+4932

1.5 OPERATORS

An operator is a symbol to perform mathematical or logical operations. Operators are used in


C program to operate on data and variables. The operators in C are classified as follows:

1. Arithmetic Operators
2. Relational Operators
3. Logical Operators
4. Assignment Operators
5. Increment and Decrement Operators
6. Conditional Operators
7. Bitwise Operators
8. Special Operators

1.5.1 Arithmetic Operators

All the basic arithmetic operations can be carried out in C. All the operators have almost the
same meaning as in other languages. Both unary and binary operations are available in C
language. Unary operations operate on a single operand.

Operator Meaning

+ Addition or Unary Plus

– Subtraction or Unary Minus

* Multiplication

/ Division

% Modulus Operator

Examples of arithmetic operators:


x+y
x-y

6|P a g e
-x + y
a*b+c
-a * b
a, b, c, x, y are known as operands. The modulus operator is a special operator in C language
which evaluates the remainder of the operands after division.

Integer Arithmetic

When an arithmetic operation is performed on two whole numbers or integers than such an
operation is called as integer arithmetic. It always gives an integer as the result. Let x = 27
and y = 5 be 2 integer numbers. Then the integer operation leads to the following results.

x + y = 32
x – y = 22
x * y = 115
x%y=2
x/y=5

In, integer division the fractional part is truncated.

Floating point Arithmetic

When an arithmetic operation is preformed on two real numbers or fraction numbers such an
operation is called floating point arithmetic. The floating point results can be truncated
according to the properties requirement. The remainder operator is not applicable for floating
point arithmetic operands.

Let x = 14.0 and y = 4.0 then

x + y = 18.0
x – y = 10.0
x * y = 56.0
x / y = 3.50

Mixed mode arithmetic

When one of the operand is real and other is an integer and if the arithmetic operation is
carried out on these 2 operands then it is called as mixed mode arithmetic. If any one operand
is of real type then the result will always be real thus 15/10.0 = 1.5

7|P a g e
1.5.2 Relational Operators

Relational operators used to compare the relationship between operands. C supports the
following relational operators.

Operator Meaning

< is less than

<= is less than or equal to

> is greater than

>= is greater than or equal to

== is equal to

A simple relational expression contains only one relational operator and takes the following
form.
exp1 relational operator exp2

Where exp1, exp2 are expressions, which may be simple constants, variables or combination
of them.

Examples: List of examples and evaluated values.

6.5 <= 25 TRUE


-65 > 0 FALSE
10 < 7 + 5 TRUE

1.5.3 Logical Operators

C has the following logical operators, used to compare or evaluate logical and relational
expressions.

Operator Meaning

&& Logical AND

|| Logical OR

! Logical NOT

8|P a g e
Logical AND (&&)

This operator evaluates two conditions or expressions with relational operators


simultaneously. If both the expressions to the left and to the right of the logical operator is
true then that compound expression is true.

Example

a > b && x = = 10

The expression to the left is a > b and that on the right is x == 10 the whole expression is true
only if both expressions are true i.e., if a is greater than b and x is equal to 10.

Logical OR (||)

The logical OR is used to combine two expressions or the condition evaluates to true if any
one of the expressions is true.

Example

a < m || a < n

The expression evaluates to true if any one of them is true or if both of them are true. It
evaluates to true if a is less than either m or n and when a is less than both m and n.

Logical NOT (!)

The logical not operator takes single expression and evaluates to true if the expression is false
and evaluates to false if the expression is true. In other words it just reverses the value of the
expression.

For example

! (x >= y)

The expression evaluates to true only if the value of x is less than y

1.5.4 Assignment Operators

The Assignment Operator evaluates an expression on the right of the expression and
substitutes it to the value or variable on the left of the expression.

9|P a g e
Example

x=a+b The value of a + b is evaluated and substituted to the variable x.

In addition, C has a set of shorthand assignment operators of the form.

var oper = exp;

Here var is a variable, exp is an expression and oper is a C binary arithmetic operator. The
operator oper = is known as shorthand assignment operator

Example

x += 1 is same as x = x + 1
The commonly used shorthand assignment operators are as follows:
Assignment operators:

Statement with simple Statement with


assignment operator shorthand operator

a=a+1 a += 1

a=a–1 a -= 1

a = a * (n+1) a *= (n+1)

a = a / (n+1) a /= (n+1)

a=a%b a %= b

Example:
#define N 100 //creates a variable N with constant value 100
#define A 2 //creates a variable A with constant value 2

main() //start of the program


{
int a; //variable a declaration
a = A; //assigns value 2 to a

while (a < N) //while value of a is less than N

10 | P a g e
{ //evaluate or do the following
printf(“%d \n”, a); //print the current value of a
a *= a; // a = a * a
} //end of the loop
} //end of the program

Output

2
4
16

1.5.5 Increment and Decrement Operators

The increment and decrement operators are one of the unary operators which are very useful
in C language. They are extensively used in for and while loops. The syntax of the operators
is given below

1. ++ variable name
2. variable name++
3. – variable name
4. variable name –

The increment operator ++ adds the value 1 to the current value of operand and the decrement
operator – – subtracts the value 1 from the current value of operand. ++variable name and
variable name++ mean the same thing when they form statements independently, behave
differently when they are used in expression on the right hand side of an assignment
statement.

Consider the following:


m = 5;
y = ++m; (prefix)
In this case the value of y and m would be 6
Suppose if we rewrite the above statement as
m = 5;
y = m++; (post fix)

Then, the value of y will be 5 and that of m will be 6. A prefix operator first adds 1 to the
operand and then the result is assigned to the variable on the left. On the other hand, a postfix
operator first assigns the value to the variable on the left and then increments the operand.

11 | P a g e
1.5.6 Conditional Operator or Ternary Operator ( ?: )

The conditional operator consists of two symbols, the question mark (?) and the colon (:) .
The syntax for a ternary operator is as follows:

exp1 ? exp2 : exp3

The ternary operator works as follows:

exp1 is evaluated first. If the expression is true then exp2 is evaluated & its value becomes
the value of the expression. If exp1 is false, exp3 is evaluated and its value becomes the value
of the expression.

For example

a = 10;
b = 15;
x = (a > b) ? a : b

Here ‘x’ will be assigned to the value of ‘b’. The condition follows that the expression is
false therefore b is assigned to x.

/* Example : to find the maximum value using conditional operator)


#include<stdio.h>
void main() //start of the program
{
int i, j, larger; //declaration of variables
printf (“Input 2 integers : ”); //ask the user to input 2 numbers
scanf(“%d %d”,&i, &j); //take the number from standard input and store it
larger = i > j ? i : j; //evaluation using ternary operator
printf(“The largest of two numbers is %d \n”, larger); // print the largest number
} // end of the program

Output
Input two integers: 34, 45
The largest of two numbers is 45

1.5.7. Bitwise Operators

C has a distinction of supporting special operators known as bitwise operators for


manipulation data at bit level. A bitwise operator operates on each bit of data. Those

12 | P a g e
operators are used for testing, complementing or shifting bits to the right on left. Bitwise
operators may not be applied to a float or double.

Operator Meaning

& Bitwise AND

| Bitwise OR

^ Bitwise Exclusive

<< Shift left

>> Shift right

Type char is one byte in size. This means it is made up of 8 distinct bits or binary digits
normally designated as illustrated below with Bit 0 being the Least Significant Bit (LSB) and
Bit 7 being the Most Significant Bit (MSB). The value represented below is 13 in decimal.

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0


0 0 0 0 1 1 0 1

An integer on a 16 bit OS is two bytes in size and Bit 15 will be the MSB while on a 32 bit
system the integer is four bytes in size with Bit 31 as the MSB.

Bitwise AND (&)

If any two bits in the same position are 1 then the resultant bit in that position is 1 otherwise it
is 0.

For Example :
1011 0010 (178)
& 0011 1111 (63)
= 0011 0010 (50)

Bitwise OR (|)

Note : If either bit in corresponding positions is 1 then resultant bit in that position is 1.
For Example :
1011 0010 (178)
| 0011 1111 (63)
= 1011 1111 (191)

13 | P a g e
Bitwise XOR ( ^)

Note: If the bits in corresponding positions are different then the resultant bit is 1.

For Example :
1011 0010 (178)
^ 0011 1111 (63)
= 1000 1101 (141)

Shift Operators (<< and >>)

The bits are shifted to left or right by a specified number of places.

Syntax : variable << number of places


variable >> number of places

For Example :-
2 << 2 = 8
i.e.
0000 0010 becomes 0000 1000

NOTE : shift left by one place multiplies by 2


shift right by one place divides by 2

Ones Complement

RULE : Reverses the state of each bit.

For Example :-
1101 0011 becomes 0010 1100

The bitwise operators are most commonly used in system level programming where
individual bits of an integer will represent certain real life entities which are either on or off,
one or zero. The programmer will need to be able to manipulate individual bits directly in
these situations.
A mask variable which allows us to ignore certain bit positions and concentrate the operation
only on those of specific interest to us is almost always used in these situations. The value
given to the mask variable depends on the operator being used and the result required.

For Example :- To clear bit 7 of a char variable.

14 | P a g e
char ch = 89 ; // any value

char mask = 127 ; // 0111 1111

ch = ch & mask ; // or ch &= mask ;

For Example :- To set bit 1 of an integer variable.

int i = 234 ; // any value

int mask = 2 ; // a 1 in bit position 2

i |= mask ;

1.1.8. Special Operators

C supports some special operators of interest such as comma operator, size of operator,
pointer operators (& and *) and member selection operators (. and ->). The size of and the
comma operators are discussed in this section.

The Comma Operator


The comma operator can be used to link related expressions together. A comma-linked list of
expressions are evaluated left to right and value of right most expression is the value of the
combined expression.

For example the statement


value = (x = 10, y = 5, x + y);

First assigns 10 to x and 5 to y and finally assigns 15 to value. Since comma has the lowest
precedence in operators the parenthesis is necessary. Some examples of comma operator are

In for loops:
for (n=1, m=10, n <=m; n++,m++)
In while loops
while (c=getchar(), c != ‘10’)
Exchanging values.

t = x, x = y, y = t;

The size of Operator


The operator size of gives the size of the data type or variable in terms of bytes occupied in
the memory. The operand may be a variable, a constant or a data type qualifier.

15 | P a g e
Example

m = sizeof (sum);
n = sizeof (long int);
k = sizeof (235L);

The size of operator is normally used to determine the length of arrays and structures when
their sizes are not known to the programmer. It is also used to allocate memory space
dynamically to variables during the execution of the program.

Example: Program that employs different kinds of operators. The results of their evaluation
are also shown in comparison.

.main() //start of program


{
int a, b, c, d; //declaration of variables
a = 15; b = 10; c = ++a-b; //assign values to variables
printf (“a = %d, b = %d, c = %d\n”, a,b,c); //print the values
d=b++ + a;
printf (“a = %d, b = %d, d = %d\n, a,b,d);
printf (“a / b = %d\n, a / b);
printf (“a %% b = %d\n, a % b);
printf (“a *= b = %d\n, a *= b);
printf (“%d\n, (c > d) ? 1 : 0 );
printf (“%d\n, (c < d) ? 1 : 0 );
}

Notice the way the increment operator ++ works when used in an expression. In the statement
c = ++a – b; new value a = 16 is used thus giving value 6 to C. That is, a is incremented by 1
before using in expression.

However in the statement d = b++ + a; The old value b = 10 is used in the expression. Here b
is incremented after it is used in the expression.

We can print the character % by placing it immediately after another % character in the
control string. This is illustrated by the statement.

printf(“a %% b = %d\n”, a%b);

This program also illustrates that the expression

c>d?1:0

Assumes, the value 0 when c is less than d and 1 when c is greater than d.

16 | P a g e
1.6 C VARIABLES

A variable is a named piece of memory which is used to hold a value which may be modified
by the program. A variable thus has three attributes that are of interest to us : its type, its
value and its address.

The variable’s type informs the type and range of values it can represent and how much
memory is used to store that value. The variable’s address informs where in memory the
variable is located.
All C variables must be declared as follows:
type variable-list ;
For Example :
int i ;
char a, b, ch ;

Variables are declared in three general areas in a C program.


When declared inside function, as follows they are termed local variables and are visible (or
accessible) within the function ( or code block ) only.

void main()
{
int i, j ;
...
}

A local variable is created i.e. allocated memory for storage upon entry into the code block in
which it is declared and is destroyed i.e. its memory is released on exit. This means that
values cannot be stored in these variables for use in any subsequent calls to the function .

When declared outside function, they are termed as global variables and are visible
throughout the file or have file scope. These variables are created at program start-up and can
be used for the lifetime of the program.

int i ;
void main()
{
...
}
When declared within the braces of a function they are termed the formal parameters of the
function.
int func1( int a, char b ) ;

17 | P a g e
Variable Names

Names of variables and functions in C are called identifiers and are case sensitive. The first
character of an identifier must be either a letter or an underscore while the remaining
characters may be letters, numbers, or underscores. Identifiers in C can be up to 31 characters
in length.

Initialising Variables

When variables are declared in a program it just means that an appropriate amount of
memory is allocated to them for their exclusive use. This memory however is not initialized
to zero or to any other value automatically and so will contain random values unless
specifically initialized before use.

Syntax :- type var-name = constant ;

For Example :-
char ch = 'a' ;
double d = 12.2323 ;
int i, j = 20 ; /* note in this case i is not initialised */

Constants

C constant is usually just the written version of a number. For example 1, 0, 5.73, 12.5e9.
We can specify our constants in octal or hexadecimal, or force them to be treated as long
integers.

 Octal constants are written with a leading zero - 015.


 Hexadecimal constants are written with a leading 0x - 0x1ae.
 Long constants are written with a trailing L - 890L.

Character constants are usually just the character enclosed in single quotes; 'a', 'b', 'c'. Some
characters can't be represented in this way, so we use a 2 character sequence.

In addition, a required bit pattern can be specified using its octal equivalent.

'\044' produces bit pattern 00100100.

18 | P a g e
Character constants are rarely used, since string constants are more convenient. A string
constant is surrounded by double quotes e.g. "Brian and Dennis". The string is actually stored
as an array of characters. The null character '\0' is automatically placed at the end of such a
string to act as a string terminator.

Constant is a special types of variable which can not be changed at the time of execution.
Syntax:

const int a=20;


const float phi = 3.14;

Console Input / Output

This section introduces some of the more common input and output functions provided in the
C standard library.

printf()

The printf() function is used for formatted output and uses a control string which is made up
of a series of format specifiers to govern how it prints out the values of the variables or
constants required. The more common format specifiers are given below

%c character %f floating point


%d signed integer %lf double floating point
%i signed integer %e exponential notation
%u unsigned integer %s string
%ld signed long %x unsigned
hexadecimal
%lu unsigned long %o unsigned octal
%% prints a % sign

Example 1:
int i ;
printf( "%d", i ) ;

The printf() function takes a variable number of arguments. As shown in the example 1, two
arguments are required, the format string and the variable i. The value of i is substituted for
the format specifier %d which specifies how the value is to be displayed, in this case as a
signed integer.

Example 2 :-

int i = 10, j = 20 ;

19 | P a g e
char ch = 'a' ;
double f = 23421.2345 ;

printf( "%d + %d", i, j ) ; /* values are substituted from


the variable list in order as required */
printf( "%c", ch ) ;

printf( "%s", "Hello World\n" ) ;


printf( "The value of f is : %lf", f ) ;/*Output as : 23421.2345 */
printf( "f in exponential form : %e", f ) ; /* Output as : 2.34212345e+4

Field Width Specifiers

Field width specifiers are used in the control string to format the numbers or characters to
print appropriately .

Syntax :- %[total width printed][.decimal places printed]format specifier

where square braces indicate optional arguments.

For Example :-
int i = 15 ;
float f = 13.3576 ;
printf( "%3d", i ) ; /* prints "_15 " where _ indicates a space
character */
printf( "%6.2f", f ) ; /* prints "_13.36" which has a total width
of 6 and displays 2 decimal places */
printf( “%*.*f”, 6,2,f ) ; /* prints "_13.36" as above. Here * is used as replacement
character for field widths */

There are also a number of flags that can be used in conjunction with field width specifiers to
modify the output format. These are placed directly after the % sign. A - (minus sign) causes
the output to be left-justified within the specified field, a + (plus sign) displays a plus sign
preceding positive values and a minus preceding negative values, and a 0 (zero) causes a field
to be padded using zeros rather than space characters.

scanf()

This function is similar to the printf function except that it is used for formatted input.
The format specifiers have the same meaning as for printf() and the space character or
the newline character are normally used as delimiters between different inputs.

20 | P a g e
For Example :-

int i, d ;
char c ;
float f ;

scanf( "%d", &i ) ;

scanf( "%d %c %f", &d, &c, &f ) ; /* e.g. type "10_x_1.234RET" */

scanf( "%d:%c", &i, &c ) ; /* e.g. type "10:xRET" */

The & character is the address of operator in C, it returns the address in memory of the
variable it acts on

Note that while the space and newline characters are normally used as delimiters between
input fields the actual delimiters specified in the format string of the scanf statement must be
reproduced at the keyboard.

The scanf function has a return value which represents the number of fields.

For Example :-
num = scanf( “%c %d”, &ch, &i );

This scanf call requires two fields, a character and an integer, to be read in so the value
placed in num after the call should be 2 if this was successful. However if the input was “a
bc” then the first character field will be read correctly as ‘a’ but the integer field will not be
converted correctly as the function cannot reconcile “bc” as an integer. Thus the function will
return 1 indicating that one field was successfully converted. Thus to be safe the return value
of the scanf function should be checked always and some appropriate action taken if the
value is incorrect.

getchar() and putchar()

These functions are used to input and output single characters. The getchar() function reads
the ASCII value of a character input at the keyboard and displays the character while
putchar() displays a character on the standard output device i.e. the screen.

For Example :-
char ch1, ch2 ;

ch1 = getchar() ;

21 | P a g e
ch2 = 'a' ;
putchar( ch2 ) ;

Note : The input functions described above, scanf() and getchar() are termed buffered input
functions. This means that whatever the user types at the keyboard is first stored in a data
buffer and is not actually read into the program until either the buffer fills up and has to be
flushed or until the user flushes the buffer by hitting RET whereupon the required data is read
into the program. The important thing to remember with buffered input is that no matter how
much data is taken into the buffer when it is flushed the program just reads as much data as it
needs from the start of the buffer allowing whatever else that may be in the buffer to be
discarded.

For Example :-
char ch1, ch2;

printf( "Enter two characters : " ) ;


ch1 = getchar() ;
ch2 = getchar() ;
printf( "\n The characters are %c and %c\n", ch1, ch2 ) ;

In the above code segment if the input is "abcdef”, the first two characters are read into the
variables all the others being discarded, but control does not return to the program until the
RET is hit and the buffer flushed. If the input was "aRET" then a would be placed in ch1 and
RET in ch2.

_flushall()

The _flushall function writes the contents of all output buffers to the screen and clears
the contents of all input buffers. The next input operation (if there is one) then reads new data
from the input device into the buffers.

This function should be used always in conjunction with the buffered input functions to clear
out unwanted characters from the buffer after each input call.

getch() and getche()

These functions perform the same operation as getchar() except that they are unbuffered input
functions i.e. it is not necessary to type RET to cause the values to be read into the program
they are read in immediately the key is pressed. getche() echoes the character hit to the screen
while getch() does not.

For example :-
char ch ;
ch = getch() ;

22 | P a g e
First C Program

A C program consists of one or more functions or code modules. These are essentially groups
of instructions that are to be executed as a unit in a given order and that can be referenced by
a unique name. Each C program must contain a main() function. This is the first function
called when the program starts to run. Note that while "main" is not a C keyword and hence
not reserved it should be used only in this context.

A program in C is traditionally arranged in the following order but not strictly as a rule.

Function prototypes and global data


declarations

The main() function

Function definitions

Consider first a simple C program which simply prints a line of text to the computer screen.

#include <stdio.h>
void main()
{
/* This is how comments are implemented in C
to comment out a multi-line
text as comment */
// or like this for a single line comment

printf( "This is my First C Program\n" ) ;

As you can see this program consists of just one function the mandatory main function. The
parentheses, ( ), after the word main indicate a function while the curly braces, { }, are used
to denote a block of code, i.e the sequence of instructions that make up the function.

Comments are contained within a /* ... */ pair in the case of a block comment or a double
forward slash, //, used to comment out the remains of a single line of test.

The line
printf("This is my First C Program \n " ) ;

23 | P a g e
is the only C statement in the program and must be terminated by a semicolon.
The statement calls a function called printf which causes its argument, the string of
text within the quotation marks, to be printed to the screen. The characters \n are not printed
as these characters are interpreted as special characters by the printf function in this case
printing out a newline on the screen. These characters are called escape sequences in C and
cause special actions to occur and are preceded always by the backslash character, \ .

All C compiler include a library of standard C functions such as printf which allow the
programmer to carry out routine tasks such as I/O, maths operations, etc. but which are not
part of the C language, the compiled C code merely being provided with the compiler in a
standard form.

Header files must be included which contain prototypes for the standard library functions and
declarations for the various variables or constants needed. These are normally denoted by a .h
extension and are processed automatically by a program called the Preprocessor prior to the
actual compilation of the C program.

The line
#include <stdio.h>

instructs the preprocessor to include the file stdio.h into the program before compilation so
that the definitions for the standard input/output functions including printf will be present for
the compiler. The angle braces denote that the compiler should look in the default
“INCLUDE” directory for this file. A pair of double quotes indicate that the compiler should
search in the specified path e.g.

#include “d:\myfile.h”

Note : C is case sensitive i.e. printf() and Printf() would be regarded as two different
functions.

1.7 C PROGRAMMING ENVIRONMENT

The first phase of development involves the creation and editing of a file containing the
appropriate C instructions which will be stored using a file extension of .c normally to invoke
the C compiler, e.g. fname.c.

The next step is to take the C program and to compile it into object code or machine language
code. The C compiler includes the aforementioned preprocessor which is called automatically
before the code translation takes place. This preprocessor acts on special commands or
directives from the programmer to manipulate the text of the C code before compilation
commences. These directives might involve including other source files in the file to be
compiled, replacing special symbols with specific replacement text, etc. Once this is done the

24 | P a g e
C code is translated into object code and stored in a file with the extension .obj, e.g.
fname.obj.

The final phase in building the executable program is called linking. After the compilation
stage the C code has been translated into machine recognizable code but is in a somewhat
unconnected state. The program invariably contains references to standard library functions
or functions contained in other libraries or modules which must be connected to the C
program at link time. This simply involves linking the machine code for these functions with
the program’s object code to complete the build process and produce an executable file with
an extension .exe e.g. fname.exe.

The executable program can be loaded and run from within the programming environment
itself or may be run from the host environment directly. If it executes as expected that is the
end of the task. However if this does not happen it may require the use of the debugger to
isolate any logical problems. The debugger allows us to step through the code instruction by
instruction or up to predefined break-points and to look at the values of variables in the code
in order to establish where errors are introduced.

25 | P a g e
1.8 PRECEDENCE AND ASSOCIATIVITY OF OPERATORS

When several operations are combined into one C expression the compiler has to rely on a
strict set of precedence rules to decide which operation will take preference. The precedence
of C operators is given below.

Precedence Operator Associativity


Highest ( ) [ ] -> . left to right
! ~ ++ -- +(unary) -(unary) (type) * & sizeof right to left
* / % left to right
+ - left to right
<< >> left to right
< <= > >= left to right
== != left to right
& left to right
^ left to right
| left to right
&& left to right
|| left to right
?: right to left
= += -= *= /= %= &= ^= |= <<= >>= right to left
Lowest , left to right

Operators at the top of the table have highest precedence and when combined with other
operators at the same expression level will be evaluated first.

For example take the expression

2 + 10 * 5 ;

Here * and + are being applied at the same level in the expression but which comes first ?
The answer lies in the precedence table where the * is at a higher level than the + will
consider first.

When two operators with the same precedence level are applied at the same expression level
the associativity of the operators comes into play.

For example in the expression

2+3-4;
the + and - operators are at the same precedence level but associate from left to right and so
the addition will be performed first. However in the expression

x=y=2;

26 | P a g e
as we have noted already the assignment operator associates from right to left and so the
rightmost assignment is first performed.

Note : As we have seen already parentheses can be used to supersede the precedence rules
and force evaluation along the lines we require. For example to force the addition in 2 + 10 *
5 ; to be carried out first we would write it as (2 + 10) * 5;

Type conversions in expressions

Implicit type conversion

C permits mixing of constants and variables of different types in an expression. C


automatically converts any intermediate values to the proper type so that the expression can
be evaluated without loosing any significance. This automatic type conversion is known as
implicit type conversion .

The following rules apply during evaluating expressions:

1.All short and char are automatically converted to int

1. If one operand is long double, the other will be converted to long double and result
....will be long double.
.
2. If one operand is double, the other will be converted to double and result will be
double.
.
3. If one operand is float, the other will be converted to float and result will be float.
.
4. If one of the operand is unsigned long int, the other will be converted into unsigned
....long int and result will be unsigned long int.
.
5. If one operand is long int and other is unsigned int then .
.... a. If unsigned int can be converted to long int, then unsigned int operand will be
.........converted as such and the result will be long int.
.....b. Else Both operands will be converted to unsigned long int and the result will be
.........unsigned long int.
6. If one of the operand is long int, the other will be converted to long int and the result
will be long int. .
7. If one operand is unsigned int the other will be converted to unsigned int and the
.....result will be unsigned int.

27 | P a g e
Explicit Conversion

Many times there may arise a situation where we want to force a type conversion in a way
that is different from automatic conversion,

Consider for example the calculation of number of female and male students in a class

Ratio = female_students / male_students

Since if female_students and male_students are declared as integers, the decimal part will be
rounded off and its ratio will represent a wrong figure. This problem can be solved by
converting locally one of the variables to the floating point as shown below.

Ratio = (float) female_students / male_students;

The operator float converts the female_students to floating point for the purpose of evaluation
of the expression. Then using the rule of automatic conversion, the division is performed by
floating point mode, thus retaining the fractional part of the result. The process of such a local
conversion is known as explicit conversion or casting a value. The general form is

(type_name) expression

1.9 SELECTION

if statement

The if statement is the most general method for allowing conditional execution in C.

Syntax : if ( condition )
statement body ;
else
statement body ;
or just :
if ( condition )
statement body ;

In the first more general form of the statement one of two code blocks are to be executed. If
the condition evaluates to TRUE the first statement body is executed otherwise for all other
situations the second statement body is executed.

28 | P a g e
In the second form of the statement the statement body is executed if the condition evaluates
to TRUE. No action is taken otherwise.

For Example : Program to perform integer division avoiding the division by zero case.

#include <stdio.h>
void main()
{
I nt nr, dr ;

printf( "Enter two integers for numerator, denominator :" );


scanf( "%d, %d", &nr, &dr ) ;

if ( dr != 0 )
printf( "%d / %d = %d \n", nr, dr, nr/dr );
else
printf( "Invalid operation - unable to divide by zero \n” );
}

As with all other control statements the statement body can also involve multiple statements,
again contained within curly braces.

Example :- Program to count the number of occurrences of the letter 'a' in an input stream of
characters terminated with a carriage return.

#include <stdio.h>
void main()
{
int count = 0, total = 0 ;
char ch ;
while ( ( ch = getchar() ) != 13 ) // 13 is ASCII value for carriage return
{
if ( ch == 'a' )
{
count ++ ;
printf( “\n Retrieved letter ‘a’ number %d\n”, count ) ;
}
total ++ ;
_flushall() ;
}
printf( "\n\n %d letters a typed in a total of %d letters.", count, total ) ;
}

29 | P a g e
Nested if statements

if - else statements like all other decision or iteration statements in C can be nested to
whatever extent is required. Care should be taken however to ensure that the if and else parts
of the statement are matched correctly -- the rule to follow is that the else statement matches
the most recent unmatched if statement.

For Example :-
if ( x > 0 )
if ( x > 10 )
puts ( " x is greater than zero and also greater than 10 ");
else
puts ("x is greater than zero but less than or equal to 10");

The else clause matches the most recent unmatched if clause, if ( x > 10 ). For more clarity
the above section could be rewritten as follows using curly braces with no execution penalty
:-

if ( x > 0 )
{
if ( x > 10 )
puts ( " x is greater than zero and also greater than 10 ");
else
puts ( "x is greater than zero but less than or equal to 10 ");
}

if - else - if ladder

When a programming situation requires the choice of one case from many different cases
successive if statements can be tied together forming what is sometimes called an if-else-if
ladder.

Syntax : if ( condition_1 )
statement_1 ;
else if ( condition_2 )
statement_2 ;
else if ( condition_3 )
statement_3 ;
...

else if ( condition_n )
statement_n ;

30 | P a g e
else
statement_default ;

Essentially what we have here is a complete if-else statement hanging onto each else
statement working from the bottom up.

Example : Nested If Statements

void main()
{
int secret = 101, guess, count = 0 ;
printf( “\n Try and guess my secret number.\n\n” ) ;
while ( 1 ) // infinite loop until we break out of it
{
printf( “\n Make your guess: ” ) ;
scanf( “%d”, &guess ) ;
count ++ ;
if ( guess < secret )
printf( “\nA little low. Try again.” ) ;
else if ( guess > secret )
printf( “\nA little high. Try again.” ) ;
else
{
printf( “\nOk you got it and only on attempt %d.”, count );
break ;
}
}
}

Switch Case

This is another form of the multi way decision. It is well structured, but can only be used in
certain cases where;

 Only one variable is tested, all branches must depend on the value of that variable.
The variable must be an integral type. (int, long, short or char).
 Each possible value of the variable can control a single branch. A final, catch all,
default branch may optionally be used to trap all unspecified cases.

Example:
int number;
/* Estimate a number as none, one, two, several, many */

31 | P a g e
{ switch(number) {
case 0 :
printf("None\n");
break;
case 1 :
printf("One\n");
break;
case 2 :
printf("Two\n");
break;
case 3 :
case 4 :
case 5 :
printf("Several\n");
break;
default :
printf("Many\n");
break;
}
}
Each interesting case is listed with a corresponding action. The break statement prevents any
further statements from being executed by leaving the switch. Since case 3 and case 4, there
is no break statement, they continue on allowing the same action for several values of
number.

Both if and switch constructs allow the programmer to make a selection from a number of
possible actions.

1.10 REPETITION

Looping is a way by which we can execute set of statements more than one times
continuously .In C, there are mainly three types of loops are in use :

 while Loop
 do while Loop
 For Loop

while statement

The while statement is typically used in situations where it is not known in advance how
many iterations are required.

32 | P a g e
Syntax : while ( condition )
statement body ;

FALSE
test condition

TRUE
continue
with next
iteration
statement body

end of statement

For Example : Program to sum all integers from 100 down to 1.

#include <stdio.h>
void main()
{
int sum = 0, i = 100 ;

while ( i )
sum += i-- ;// note the use of postfix decrement operator!
printf( “Sum is %d \n”, sum ) ;
}

where it should be recalled that any non-zero value is deemed TRUE in the condition section
of the statement.

A for loop is of course the more natural choice where the number of loop iterations is known
beforehand whereas a while loop caters for unexpected situations more easily. For example if
we want to continue reading input from the keyboard until the letter 'Q' is hit we might do the
following.
char ch = '\0' ; /* initialise variable to ensure it is not 'Q' */

while ( ch != 'Q' )
ch = getche() ;
or more succinctly

while ( ( ch = getche() ) != 'Q' ) ;

It is of course also possible to have nested while loops.

33 | P a g e
For Example : Program to guess a letter.

#include <stdio.h>
void main()
{
char ch, letter = 'c' ; // secret letter is ‘c’
char finish = ‘\0’ ;

while ( finish != ‘y’ || finish != ‘Y’ )


{
puts( "Guess my letter -- only 1 of 26 !" );

while( (ch=getchar() ) != letter )// note use of parentheses


{
printf( "%c is wrong -- try again\n", ch ) ;
_flushall() ; // purges I/O buffer
}
printf ( "OK you got it \n Let’s start again.\n" ) ;

letter += 3 ;// Change letter adding 3 onto ASCII value of letter


// e.g. ‘c’ + 3 = ‘f’
printf( “\n\nDo you want to continue (Y/N) ? “);
finish = getchar() ;
_flushall() ;
}
}
do while

The terminating condition in the for and while loops is always tested before the body of the
loop is executed -- so of course the body of the loop may not be executed at all.

In the do while statement on the other hand the statement body is always executed at least
once as the condition is tested at the end of the body of the loop.

Syntax : do
{
statement body ;
} while ( condition ) ;

34 | P a g e
statement body

continue
with next
iteration
TRUE
test condition

FALSE

end of statement

For Example : To read in a number from the keyboard until a value in the range 1 to 10 is
entered.

int i ;

do
{
scanf( "%d\n", &i ) ;
_flushall() ;
} while ( i < 1 && i > 10 ) ;

In this case we know at least one number is required to be read so the do-while might be the
natural choice over a normal while loop.

The for statement

The for statement is most often used in situations where the programmer knows in advance
how many times a particular set of statements are to be repeated. The for statement is
sometimes termed a counted loop.

Syntax : for ( [initialisation] ; [condition] ; [increment] )


[statement body] ;

initialisation :- this is usually an assignment to set a loop counter variable for example.
condition :- determines when loop will terminate.
increment :- defines how the loop control variable will change each time the loop is
executed.
statement body :- can be a single statement, no statement or a block of statements.

The for statement executes as follows :-

35 | P a g e
initialisation

FALSE
test condition

TRUE
continue
with next
iteration
statement body

increment

end of statement

The square braces above are to denote optional sections in the syntax but are not part of the
syntax. The semi-colons must be present in the syntax.

For Example : Program to print out all numbers from 1 to 100.

#include <stdio.h>

void main()
{
int x ;

for ( x = 1; x <= 100; x++ )


printf( "%d\n", x ) ;
}

Curly braces are used in C to denote code blocks whether in a function as in main() or as the
body of a loop.
For Example :- To print out all numbers from 1 to 100 and calculate their sum.

#include <stdio.h>

void main()
{
int x, sum = 0 ;

for ( x = 1; x <= 100; x++ )


{

36 | P a g e
printf( "%d\n", x ) ;
sum += x ;
}
printf( “\n\nSum is %d\n”, sum ) ;
}

Multiple Initialisations

C has a special operator called the comma operator which allows separate expressions to be
tied together into one statement.

For example it may be tidier to initialise two variables in a for loop as follows :-

for ( x = 0, sum = 0; x <= 100; x++ )


{
printf( "%d\n", x) ;
sum += x ;
}

Any of the four sections associated with a for loop may be omitted but the semi-colons must
be present always.

For Example :-
for ( x = 0; x < 10; )
printf( "%d\n", x++ ) ;
...
x=0;
for ( ; x < 10; x++ )
printf( "%d\n", x ) ;

An infinite loop may be created as follows

for ( ; ; )
statement body ;

or indeed by having a faulty terminating condition.

Sometimes a for statement may not even have a body to execute as in the following example
where we just want to create a time delay.

for ( t = 0; t < big_num ; t++ ) ;

or we could rewrite the example given above as follows

37 | P a g e
for ( x = 1; x <= 100; printf( "%d\n", x++ ) ) ;

The initialisation, condition and increment sections of the for statement can contain any valid
C expressions.

for ( x = 12 * 4 ; x < 34 / 2 * 47 ; x += 10 )
printf( “%d “, x ) ;

It is possible to build a nested structure of for loops, for example the following creates a large
time delay using just integer variables.

unsigned int x, y ;

for ( x = 0; x < 65535; x++ )


for ( y = 0; y < 65535; y++ ) ;

For Example : Program to produce the following table of 1 2 3 4 5


values 2 3 4 5 6
3 4 5 6 7
#include <stdio.h> 4 5 6 7 8
5 6 7 8 9
void main()
{
int j, k ;

for ( j = 1; j <= 5; j++ )


{
for ( k = j ; k < j + 5; k++ )
{
printf( "%d ", k ) ;
}
printf( “\n” ) ;
}
}

break statement

When a break statement is encountered inside a while, for, do/while or switch statement the
statement is immediately terminated and execution resumes at the next statement following
the statement.

For Example :-
...

38 | P a g e
for ( x = 1 ; x <= 10 ; x++ )
{
if ( x > 4 )
break ;

printf( “%d “ , x ) ;
}
printf( "Next executed\n" );//Output : “1 2 3 4 Next Executed”
...
continue statement

The continue statement terminates the current iteration of a while, for or do/while statement
and resumes execution back at the beginning of the loop body with the next iteration.

For Example :-
...
for ( x = 1; x <= 5; x++ )
{
if ( x == 3 )
continue ;
printf( “%d “, x ) ;
}
printf( “Finished Loop\n” ) ; // Output : “1 2 4 5 Finished Loop”
...

39 | P a g e
UNIT - II
UNIT – II

2.1 ARRAYS

Arrays are widely used data type in ‘C’ language. It is a collection of elements of similar data
type. These similar elements could be of all integers, all floats or all characters. An array of
character is called as string whereas and array of integer or float is simply called as an array.
So array may be defined as a group of elements that share a common name and that are
defined by position or index. The elements of an arrays are store in sequential order in
memory.
There are mainly two types of Arrays are used:

 One dimensional Array


 Multidimensional Array

One dimensional Array


Syntax : To declare one dimensional array

int a[10];

declares an array, named a, consisting of ten elements, each of type int.. (Arrays in
programming are similar to vectors or matrices in mathematics.) Array is represented as
follows:

In C, arrays are zero-based: the ten elements of a 10-element array are numbered from 0 to 9.
The subscript which specifies a single element of an array is simply an integer expression in
square brackets. The first element of the array is a[0], the second element is a[1], etc. You
can use these ``array subscript expressions'' anywhere you can use the name of a simple
variable, for example:

a[0] = 10;
a[1] = 20;
a[2] = a[0] + a[1];

Notice that the subscripted array references (i.e. expressions such as a[0] and a[1]) can appear
on either side of the assignment operator. It is possible to initialize some or all elements of an
array when the array is defined. The syntax looks like this:

int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

40 | P a g e
The list of values, enclosed in braces {}, separated by commas, provides the initial values for
successive elements of the array.

The subscript does not have to be a constant like 0 or 1; it can be any integral expression. For
example, it's common to loop over all elements of an array:

int i;

for(i = 0; i < 10; i = i + 1)


a[i] = 0;

This loop sets all ten elements of the array a to 0.

Arrays are a real convenience for many problems, but there is not a lot that C will do with
them for you automatically. In particular, you can neither set all elements of an array at once
nor assign one array to another; both of the assignments

a = 0; /* WRONG */

and
int b[10];
b = a; /* WRONG */

are illegal.

To set all of the elements of an array to some value, you must do so one by one, as in the loop
example above. To copy the contents of one array to another, you must again do so one by
one:
int b[10];

for(i = 0; i < 10; i = i + 1)


b[i] = a[i];

Remember that for an array declared

int a[10];

there is no element a[10]; the topmost element is a[9]. This is one reason that zero-based
loops are also common in C. Note that the for loop

for(i = 0; i < 10; i = i + 1)


...
does just what you want in this case: it starts at 0, the number 10 suggests (correctly) that it
goes through 10 iterations, but the less-than comparison means that the last trip through the

41 | P a g e
loop has i set to 9. (The comparison i <= 9 would also work, but it would be less clear and
therefore poorer style.)

Multidimensional Array

The declaration of an array of arrays looks like this:

int a2[5][7];

In above declaration, a2 is an array of 5 arrays of 7 ints or, a2 is an array of array of int. You
can think of a2 as having 5 “rows'' and 7 “columns”. (You could also treat the “first'' or inner
subscript as “x” and the second as ”y”.

To illustrate the use of multidimensional arrays, we might fill in the elements of the above
array a2 using this piece of code:

int i, j;
for(i = 0; i < 5; i = i + 1)
{
for(j = 0; j < 7; j = j + 1)
a2[i][j] = 10 * i + j;
}

This pair of nested loops sets a[1][2] to 12, a[4][1] to 41, etc. Since the first dimension of a2
is 5, the first subscripting index variable, i, runs from 0 to 4. Similarly, the second subscript
varies from 0 to 6.

We could print a2 out (in a two-dimensional way, suggesting its structure) with a similar pair
of nested loops:

for (i = 0; i < 5; i = i + 1)
{
for (j = 0; j < 7; j = j + 1)
printf ("%d\t", a2[i][j]);
printf ("\n");
}

(The character \t in the printf string is the tab character.)

Just to see more clearly what's going on, we could make the ``row'' and ``column'' subscripts
explicit by printing them, too:

for(j = 0; j < 7; j = j + 1)

42 | P a g e
printf("\t%d:", j);
printf ("\n");

for(i = 0; i < 5; i = i + 1)
{
printf("%d:", i);
for(j = 0; j < 7; j = j + 1)
printf("\t%d", a2[i][j]);
printf("\n");
}

This last fragment would print


0: 1: 2: 3: 4: 5: 6:
0: 0 1 2 3 4 5 6
1: 10 11 12 13 14 15 16
2: 20 21 22 23 24 25 26
3: 30 31 32 33 34 35 36
4: 40 41 42 43 44 45 46

2.2 FUNCTIONS

Function is a set of statements that are to be executed as a unit in a given order and that can
be referenced by a unique name. The only way to execute these statements is by invoking
them or calling them using the function’s name.

Traditional program design methodology typically involves a top-down or structured


approach to developing software solutions. The main task is first divided into a number
simpler sub-tasks. If these sub-tasks are still too complex they are subdivided further into
simpler sub-tasks, and so on until the sub-tasks become simple enough to be programmed
easily.

Functions are the highest level of the building blocks given to us in C and correspond to the
sub-tasks or logical units referred to above. The identification of functions in program design
is an important step and will in general be a continuous process subject to modification as
more becomes known about the programming problem in progress.

We have already discussed C functions such as main( ) , printf(), etc. the common trait they
share being the braces that indicate they are C functions.

Syntax : return_type function_name ( parameter_list )


{
body of function ;
}

43 | P a g e
The above is termed the function definition.

Many functions will produce a result or return some information to the point at which it is
called. These functions specify the type of this quantity via the return_type section of the
function definition. If the return type is void it indicates the function returns nothing.

The function_name may be any valid C identifier and must be unique in a particular
program. If a function requires information from the point in the program from which it is
called this may be passed to it by means of the parameter_list. The parameter list must
identify the names and types of all of the parameters to the function individually. If the
function takes no parameters the braces can be left empty or use the keyword void to indicate
that situation more clearly.

Function Prototype

The syntax of the function definition is as follows:

Syntax : return_type_spec function_name( type_par1, type_par2, etc. );

This declaration simply informs the compiler what type the function returns and what type
and how many parameters it takes. Names may or may not be given to the parameters at this
time.

For Example :- An example Function program.

#include <stdio.h> /* standard I/O function prototypes */


void Fun1( void ) ; /* prototype */
void main( void )
{
Fun1() ; // function call
}

void Fun1( ) // function definition


{
printf ( "Inside the Function\n" ) ;
}

44 | P a g e
Function Definition & Local Variables

A function definition actually defines what the function does and is essentially a discrete
block of code which cannot be accessed by any statement in any other function except by
formally calling the function. Thus any variables declared and used in a function are private
or local to that function and cannot be accessed by any other function.

For Example :-
#include <stdio.h>
void Fun1( void ) ;

void main( )
{
Fun1 () ;
}

void Fun1 ( )
{
int i ; /* local or automatic variable */
for ( i=0; i<10; i++ )
printf( "Hello to Function \n" );
}

The variable i in the Fun1function is private to the Fun1 function i.e. it can only be accessed
by code in the Fun1() function.

Local variables are classified as automatic variables because each time a function is called the
variable is automatically created and is destroyed when the function returns control to the
calling function. By created we mean that memory is set aside to store the variable’s value
and by destroyed we mean that the memory required is released. Thus a local variable cannot
hold a value between consecutive calls to the function.

Static Local Variables

The keyword static can be used to force a local variable to retain its value between function
calls.

For Example :-
#include <stdio.h>
void hello( void ) ;

void main ()
{
int i ;

45 | P a g e
for ( i = 0; i < 10; i++ )
hello ( ) ;
}

void hello( )
{
static int i = 1 ;

printf( "Hello World call number %d\n", i ++ );


}

The static int i is created and initialised to 1 when the function is first called, and then
variable retains its last value during subsequent calls to the function and is only destroyed
when the program terminates.

Note: The variables i in main() and i in hello() are completely different variables even
though they have the same name because they are private to the function in which they are
declared. The compiler distinguishes between them by giving them their own unique internal
names.

Returning a Value

The return statement is used to return a value to the calling function if necessary.

Syntax : return expression ;

If a function has a return type of type void the expression section can be omitted completely
or indeed the whole return statement can be omitted and the closing curly brace of the
function will cause execution to return appropriately to the calling function.

For Example :-
#include <stdio.h>

int hello( void ) ;


int main( )
{
int count, ch = ‘\0’;
while ( ch != 'q' )
{
count = hello( ) ;
ch = getchar() ;
_flushall() ;
}

46 | P a g e
printf( "hello was called %d times\n", i ) ;
return 0 ;
}

int hello( )
{
static int i = 1 ;
printf( "Hello World \n" ) ; // hello() keeps track of how many
times it was called
return ( i++ ) ; // and passes that information back to its
caller
}

Note: The return value of the function need not always be used when calling it. In the above
example if we are not interested in know how often hello() has been called we simply ignore
that information and invoke the function with

hello() ;

Inter Function Communication using Arguments

The types of all function arguments should be declared in the function prototype as well as in
the function definition.
Note: In C arguments are passed to functions using the call-by-value scheme. This means
that the compiler copies the value of the argument passed by the calling function into the
formal parameter list of the called function. The formal parameters of a function are local
variables of the function and are created upon entry and destroyed on exit.
Example :- Program to add two numbers.
#include <stdio.h>
int add( int, int ) ; /* prototype -- need to indicate types only */
void main ( )
{
int x, y ;
puts ( "Enter two integers ") ;
scanf( "%d %d", &x, &y) ;
printf( "%d + %d = %d\n" , x, y, add(x,y) ) ;
}
int add ( int a, int b )
{
int result ;
result = a + b ;
return result ; // parentheses used for clarity here
}

47 | P a g e
Note: In the formal parameter list of a function the parameters must be individually typed.

The add() function here has three local variables, the two formal parameters and the variable
result. There is no connection between the calling arguments, x and y, and the formal
parameters, a and b, other than that the formal parameters are initialized with the values in the
calling arguments when the function is invoked. The situation is depicted below to emphasize
the independence of the various variables.

main() add()

x Value copied a result

y Value copied b

Note: The information flow is in one direction only.

For Example :- Program to swap the values of two numbers.

#include <stdio.h>
void swap( int, int ) ;

void main( )
{
int a, b ;

printf( "Enter two numbers" ) ;


scanf( " %d %d ", &a, &b ) ;
printf( "a = %d ; b = %d \n", a, b ) ;
swap( a, b ) ;
printf( "a = %d ; b = %d \n", a, b ) ;
}

void swap( int , int ) //This is original form of declarator


int x,y; // which you may see in older texts and code
{
int t ;
t =x;
x = y;
y = t;
}

48 | P a g e
Since C uses call by value to pass parameters what we have actually done in this program is
to swap the values of the formal parameters but we have not changed the values in main().
Also since we can only return one value via the return statement we must find some other
means to alter the values in the calling function.

The solution is to use call by reference where the addresses of the calling arguments are
passed to the function parameter list and the parameters are pointers which we will encounter
later on. For example when we use the scanf() standard library function to read values from
the keyboard we use the & operator to give the address of the variables into which we want
the values placed.

Storage Classes

There are four storage class modifiers used in C which determine an identifier’s storage
duration and scope.
auto
static
register
extern

An identifier’s storage duration is the period during which that identifier exists in memory.
Some identifiers exist for a short time only, some are repeatedly created and destroyed and
some exist for the entire duration of the program. An identifier’s scope specifies what
sections of code it is accessible from.

The auto storage class is implicitly the default storage class used and simply specifies a
normal local variable which is visible within its own code block only and which is created
and destroyed automatically upon entry and exit respectively from the code block.
The register storage class also specifies a normal local variable but it also requests that the
compiler store a variable so that it may be accessed as quickly as possible, possibly from a
CPU register.

The static storage class causes a local variable to become permanent within its own code
block i.e. it retains its memory space and hence its value between function calls.

When applied to global variables the static modifier causes them to be visible only within the
physical source file that contains them i.e. to have file scope. Whereas the extern modifier
which is the implicit default for global variables enables them to be accessed in more than
one source file.

For example, if two C source code files to be compiled together to give one executable and
where one specific global variable needs to be used by both the extern class allows the
programmer to inform the compiler of the existence of this global variable in both files.

49 | P a g e
2.3 RECURSION

A recursive function is a function that calls itself either directly or indirectly through another
function. Recursive function calling is often the simplest method to eventually simplified into
a series of more basic operations of the same type as the original complex operation.

This is especially true of certain types of mathematical functions. For example to evaluate the
factorial of a number, n

n! = n * n-1 * n-2 * ... * 3 * 2 * 1.

We can simplify this operation into

n! = n * (n-1)!

where the original problem has been reduced in complexity slightly. We continue this process
until we get the problem down to a task that may be solved directly, in this case as far as
evaluating the factorial of 1 which is simply 1.

So a recursive function to evaluate the factorial of a number will simply keep calling itself
until the argument is 1. All of the previous (n-1) recursive calls will still be active waiting
until the simplest problem is solved before the more complex intermediate steps can be built
back up giving the final solution.

For Example : Program to evaluate the factorial of a number using recursion.

#include <stdio.h>
short factorial( short ) ;
void main()
{
int i ;

printf(“Enter an integer and i will try to calculate its factorial : “ ) ;


scanf( “%d”, &i ) ;
printf( “\n\nThe factorial of %d, %d! is %d\n”, i, i, factorial( i ) ) ;
}

int factorial( int num )


{
if ( num <= 1 )
return 1 ;
else
return ( num * factorial( num - 1 ) ) ;
}

50 | P a g e
This program will not work very well as is because the values of factorials grow very large
very quickly. For example the value of 8! is 40320 which is too large to be held so integer
overflow will occur when the value entered is greater. Can you offer a solution to this ?

In certain situations programs with recursive functions can be slower than those without
because there is a time delay in actually calling the function and passing parameters to it.
There is also a memory penalty involved. If a large number of recursive calls are needed this
means that there are that many functions active at that time which may exhaust the machine’s
memory resources. Each one of these function calls has to maintain its own set of parameters
on the program stack.

Another Example Function to Find GCD of given 2 numbers using Recursive Function

#include <stdio.h>
int GCD ( int, int);
void main()
{
int a, b, c, d, e, result ;

printf(“Enter 5 numbers, i will calculate their GCD: “ ) ;


scanf( “%d%d%d%d%d”, &a, &b, &c, &d, &e);
result = GCD( GCD( GCD ( GCD(a,b), c) c) e) ;
printf( “\n\nThe GCD of %d, %d, %d,, %d, and %d is %d\n”, a, b,c,d,e,result ) ;
}

int GCD( int m, int n)


{
int r = m%n;
if ( r == 0 )
return n ;
else
return (GCD( n, r) ) ;
}

Here is a recursive version of the Fibonacci function.

int fib(int num)


/* Fibonacci value of a number */
{
switch(num)
{
case 0:
return(0);

51 | P a g e
break;
case 1:
return(1);
break;
default: /* Including recursive calls */
return(fib(num - 1) + fib(num - 2));
break;
}
}

2.4 PREPROCESSOR COMMANDS

The C preprocessor is a macro processor that is used automatically by the C compiler to


transform your program before compilation. It is called a macro processor because it allows
you to define macros. All Preprocessor Commands begins with #. The C preprocessor is
intended to be used only with C, C++, and Objective-C source code.

Include Syntax (#include)

Both user and system header files are included using the preprocessing directive `#include'. It
has two variants:

#include <file>

This variant is used for system header files. It searches for a file named file in a standard list
of system directories.

#include "file"

This variant is used for header files of your own program. It searches for a file named file
first in the directory containing the current file, then in the quote directories and then the
same directories used for <file>.

The argument of `#include', whether delimited with quote marks or angle brackets, behaves
like a string constant in that comments are not recognized, and macro names are not
expanded. Thus, #include <x/*y> specifies inclusion of a system header file named x/*y.

However, if backslashes occur within file, they are considered ordinary text characters, not
escape characters. None of the character escape sequences appropriate to string constants in C
are processed. Thus, #include "x\n\\y" specifies a filename containing three backslashes.
(Some systems interpret `\' as a pathname separator. All of these also interpret `/' the same
way. It is most portable to use only `/'.)

It is an error if there is anything (other than comments) on the line after the file name.

52 | P a g e
Macro Definitionss (#define)

An object-like macro is a simple identifier which will be replaced by a code fragment. It is


called object-like because it looks like a data object in code that uses it. They are most
commonly used to give symbolic names to numeric constants.

You create macros with the `#define' directive. `#define' is followed by the name of the
macro and then the token sequence it should be an abbreviation for, which is variously
referred to as the macro's body, expansion or replacement list. For example,

#define BUFFER_SIZE 1024

defines a macro named BUFFER_SIZE as an abbreviation for the token 1024. If somewhere
after this `#define' directive there comes a C statement of the form .

foo = (char *) malloc (BUFFER_SIZE);

then the C preprocessor will recognize and expand the macro BUFFER_SIZE. The C
compiler will see the same tokens as it would if you had written .

foo = (char *) malloc (1024);

By convention, macro names are written in uppercase. Programs are easier to read when it is
possible to tell at a glance which names are macros.

The macro's body ends at the end of the `#define' line. You may continue the definition onto
multiple lines, if necessary, using backslash-newline. When the macro is expanded, however,
it will all come out on one line. For example,

#define NUMBERS 1, \
2, \
3
int x[] = { NUMBERS };
==> int x[] = { 1, 2, 3 };

The most common visible consequence of this is surprising line numbers in error messages.

There is no restriction on what can go in a macro body provided it decomposes into valid
preprocessing tokens. Parentheses need not balance, and the body need not resemble valid C
code. The C preprocessor scans your program sequentially. Macro definitions take effect at
the place you write them. Therefore, the following input to the C preprocessor

foo = X;
#define X 4
bar = X;

53 | P a g e
produces

foo = X;
bar = 4;

When the preprocessor expands a macro name, the macro's expansion replaces the macro
invocation, then the expansion is examined for more macros to expand. For example,

#define TABLESIZE BUFSIZE


#define BUFSIZE 1024
TABLESIZE
==> BUFSIZE
==> 1024

TABLESIZE is expanded first to produce BUFSIZE, then that macro is expanded to produce
the final result, 1024.

Notice that BUFSIZE was not defined when TABLESIZE was defined. The `#define' for
TABLESIZE uses exactly the expansion you specify—in this case, BUFSIZE—and does not
check to see whether it too contains macro names. Only when you use TABLESIZE is the
result of its expansion scanned for more macro names.

This makes a difference if you change the definition of BUFSIZE at some point in the source
file. TABLESIZE, defined as shown, will always expand using the definition of BUFSIZE
that is currently in effect:

#define BUFSIZE 1020


#define TABLESIZE BUFSIZE
#undef BUFSIZE
#define BUFSIZE 37
Conditional Compilation (#def, #ifdef)

A conditional in the C preprocessor begins with a conditional directive: `#if', `#ifdef' or


`#ifndef'.

 Ifdef
 If
 Defined
 Else
 Elif

Ifdef

The simplest sort of conditional is

54 | P a g e
#ifdef MACRO

controlled text

#endif /* MACRO */

This block is called a conditional group. controlled text will be included in the output of the
preprocessor if and only if MACRO is defined. We say that the conditional succeeds if
MACRO is defined, fails if it is not.

The controlled text inside of a conditional can include preprocessing directives. They are
executed only if the conditional succeeds. You can nest conditional groups inside other
conditional groups, but they must be completely nested. In other words, `#endif' always
matches the nearest `#ifdef' (or `#ifndef', or `#if'). Also, you cannot start a conditional group
in one file and end it in another.

The comment following the `#endif' is not required, but it is a good practice if there is a lot of
controlled text, because it helps people match the `#endif' to the corresponding `#ifdef'.
Sometimes you wish to use some code if a macro is not defined. You can do this by writing
`#ifndef' instead of `#ifdef'. One common use of `#ifndef' is to include code only the first
time a header file is included.

If

The `#if' directive allows you to test the value of an arithmetic expression, rather than the
mere existence of one macro. Its syntax is

#if expression

controlled text

#endif /* expression */

expression is a C expression of integer type, subject to stringent restrictions. It may contain

 Integer constants.
 Character constants, which are interpreted as they would be in normal code.
 Arithmetic operators for addition, subtraction, multiplication, division, bitwise
operations, shifts, comparisons, and logical operations (&& and ||). The latter two
obey the usual short-circuiting rules of standard C.
 Macros. All macros in the expression are expanded before actual computation of the
expression's value begins.
 Uses of the defined operator, which lets you check whether macros are defined in the
middle of an `#if'.

55 | P a g e
Defined

The special operator defined is used in `#if' and `#elif' expressions to test whether a certain
name is defined as a macro. defined name and defined (name) are both expressions whose
value is 1 if name is defined as a macro at the current point in the program, and 0 otherwise.
Thus, #if defined MACRO is precisely equivalent to #ifdef MACRO.

defined is useful when you wish to test more than one macro for existence at once. For
example,

#if defined (__vax__) || defined (__ns16000__)

would succeed if either of the names __vax__ or __ns16000__ is defined as a macro.

Conditionals written like this:

#if defined BUFSIZE && BUFSIZE >= 1024

can generally be simplified to just #if BUFSIZE >= 1024, since if BUFSIZE is not defined,
then it is interpreted as the value zero.

If the defined operator appears as a result of a macro expansion, the C standard says the
behavior is undefined..

Else

The `#else' directive can be added to a conditional to provide alternative text to be used if the
condition fails. This is what it looks like:

#if expression
text-if-true
#else /* Not expression */
text-if-false
#endif /* Not expression */

If expression is nonzero, the text-if-true is included and the text-if-false is skipped. If


expression is zero, the opposite happens.

You can use `#else' with `#ifdef' and `#ifndef', too.

Elif

One common case of nested conditionals is used to check for more than two possible
alternatives. For example, you might have

56 | P a g e
#if X == 1
...
#else /* X != 1 */
#if X == 2
...
#else /* X != 2 */
...
#endif /* X != 2 */
#endif /* X != 1 */

Another conditional directive, `#elif', allows this to be abbreviated as follows:

#if X == 1
...
#elif X == 2
...
#else /* X != 2 and X != 1*/
...
#endif /* X != 2 and X != 1*/

`#elif' stands for “else if”. Like `#else', it goes in the middle of a conditional group and
subdivides it; it does not require a matching `#endif' of its own. Like `#if', the `#elif' directive
includes an expression to be tested. The text following the `#elif' is processed only if the
original `#if'-condition failed and the `#elif' condition succeeds.

More than one `#elif' can go in the same conditional group. Then the text after each `#elif' is
processed only if the `#elif' condition succeeds after the original `#if' and all previous `#elif'
directives within it have failed.

`#else' is allowed after any number of `#elif' directives, but `#elif' may not follow `#else'.

57 | P a g e
UNIT - III
UNIT - III

3.1 POINTERS

A pointer is a variable that is used to store a memory address. Most commonly the address is
the location of another variable in memory. If one variable holds the address of another then
it is said to point to the second variable.

Address Value Variable


1000
1004 1012 ivar_ptr
1008
1012 23 ivar
1016

In the above illustration ivar is a variable of type int with a value 23 and stored at memory
location 1012. ivar_ptr is a variable of type pointer to int which has a value of 1012 and is
stored at memory location 1004. Thus ivar_ptr is said to point to the variable ivar and allows
us to refer indirectly to it in memory.

Note : It should be remembered that ivar_ptr is a variable itself with a specific piece of
memory associated with it, in this 32-bit case four bytes at address 1004 which is used to
store an address.

Pointer Variables

Pointers like all other variables in C must be declared as such prior to use.

Syntax : type *ptr ;

which indicates that ptr is a pointer to a variable of type type. For example

int *ptr ;

declares a pointer ptr to variables of type int.

Note: The type of the pointer variable ptr is int *. The declaration of a pointer variable
normally sets aside just two or four bytes of storage for the pointer whatever it is defined to
point to.

In 16-bit systems two byte pointers are termed near pointers and are used in small memory
model programs where all addresses are just segment offset addresses and 16 bits in length.
In larger memory model programs addresses include segment and offset addresses and are 32

58 | P a g e
bits long and thus pointers are 4 bytes in size and are termed far pointers. In 32-bit systems
we have a flat address system where every part of memory is accessible using 32-bit pointers.

Pointer Operators * and &

& is a unary operator that returns the address of its operand which must be a variable.

For Example :-

int *m ;
int count=125, i ;/* m is a pointer to int, count, i are integers */
m = &count ;

The address of the variable count is placed in the pointer variable m.

The * operator is the complement of the address operator & and is normally termed the
indirection operator. Like the & operator it is a unary operator and it returns the value of the
variable located at the address its operand stores.

For Example :-

i = *m ;

assigns the value which is located at the memory location whose address is stored in m, to the
integer i. So essentially in this case we have assigned the value of the variable count to the
variable i. The final situation is illustrated below.

indirection
count i m
125 125 1000
1000 1724 1824

One of the most frequent causes of error when dealing with pointers is using an un-initialized
pointer. Pointers should be initialized when they are declared or in an assignment statement.
Like any variable if you do not specifically assign a value to a pointer variable it may contain
any value. This is extremely dangerous when dealing with pointers because the pointer may
point to any arbitrary location in memory, possibly to an unused location but also possibly to
a memory location that is used by the operating system. If your program tries to change the
value at this address it may cause the whole system to crash. Therefore it is important to

59 | P a g e
initialise all pointers before use either explicitly in your program or when defining the
pointer.

A pointer may also be initialised to 0 ( zero ) or NULL which means it is pointing at nothing.
This will cause a run-time error if the pointer is inadvertently used in this state. It is useful to
be able to test if a pointer has a null value or not as a means of determining if it is pointing at
something useful in a program.
Note: NULL is #defined in <stdio.h>.
For Example :-
int var1, var2 ;
int *ptr1, *ptr2 = &var2 ;
int *ptr3 = NULL ;
...
ptr1 = &var1 ;
ptr1 and ptr2 are now pointing to data locations within the program.
Call by Reference

Recall when we wanted to swap two values using a function we were unable to actually swap
the calling parameters as the call by value standard was employed. The solution to the
problem is to use call by reference which is implemented in C by using pointers as is
illustrated in the following example.

#include <stdio.h>
void swap( int *, int * ) ;
void main( )
{
int a, b ;
printf( "Enter two numbers" ) ;
scanf( " %d %d ", &a, &b ) ;
printf( "a = %d ; b = %d \n", a, b ) ;
swap( &a, &b ) ;
printf( "a = %d ; b = %d \n", a, b ) ;
}
void swap ( int *x, int *y )
{
int t ;

t = *x ;
*x = *y ;
*y = t ;
}

60 | P a g e
The swap() function is now written to take integer pointers as parameters and so is called in
main() as
swap( &a, &b ) ;

where the addresses of the variables are passed and copied into the pointer variables in the
parameter list of swap(). These pointers must be de-referenced to manipulate the values, and
it is values in the same memory locations as in main() we are swapping unlike the previous
version of swap where we were only swapping local data values.

In our earlier call-by-value version of the program we called the function from main() as
swap(a,b); and the values of these two calling arguments were copied into the formal
arguments of function swap.

In our call-by-reference version, formal arguments are pointers to int and it is the addresses
contained in these pointers, (i.e. the pointer values), that are copied here into the formal
arguments of the function. However when we de-reference these pointers we are accessing
the values in the main() function as their addresses do not change.

Pointers and Arrays

There is a very close relationship between pointer and arrays in C. As we have seen already
the name of an array ( or string ) is actually the address in memory of the array and so it is
essentially a constant pointer.

For Example :-
char str[80], *ptr ;
ptr = str ;/* causes ptr to point to start of string str */
ptr = &str[0] ; /* this performs the same as above */

Instead of using the normal method of accessing array elements using an index we can
use pointers in much the same way to access them as follows.

char str[80], *ptr , ch;

ptr = str ; // position the pointer appropriately

*ptr = 'a' ; // access first element i.e. str[0]


ch = *( ptr + 1 ) ; // access second element i.e. str[1]

Thus *( array + index ) is equivalent to array[index].

Note that the parentheses are necessary above as the precedence of * is higher than that of +.
The expression

61 | P a g e
ch = *ptr + 1 ;

For example says to access the character pointed to by ptr ( str[0] in above example with
value ‘a’) and to add the value 1 to it. This causes the ASCII value of ‘a’ to be incremented
by 1 so that the value assigned to the variable ch is ‘b’.

int x[10], *ptr ;


ptr = x ;
ptr[4] = 10 ; /* accesses element 5 of array by indexing a pointer */

Pointer Arithmetic

Pointer variables can be manipulated in certain limited ways. Many of the manipulations are
most useful when dealing with arrays which are stored in contiguous memory locations.
Knowing the layout of memory enables us to traverse it using a pointer.
Assignment
int count, *p1, *p2 ;
p1 = &count ; // assign the address of a variable directly
p2 = p1 ; // assign the value of another pointer variable, an address

Addition / Subtraction

The value a pointer holds is just the address of a variable in memory, which is normally a
four byte entity. It is possible to modify this address by integer addition and subtraction if
necessary. Consider the following we assume a 32-bit system and hence 32-bit integers.

int *ptr ; Address Value


int array[3] = { 100, 101, 102 } ; ptr 1000 2008
ptr = array ;  
array[0] 2008 100
array[1] 2012 101
array[2] 2016 102

We now have the pointer variable ptr pointing at the start of array which is stored at memory
location 2008 in our illustration. Since we know that element array[1] is stored at address
2012 directly after element array[0] we could perform the following to access its value using
the pointer.

ptr += 1 ;

This surprisingly will cause ptr to hold the value 1012 which is the address of array[1], so we
can access the value of element array[1]. The reason for this is that ptr is defined to be a
pointer to type int, which are four bytes in size on a 32-bit system. When we add 1 to ptr what

62 | P a g e
we want to happen is to point to the next integer in memory. Since an integer requires four
bytes of storage the compiler increments ptr by 4. Likewise a pointer to type char would be
incremented by 1, a pointer to float by 4, etc.

Similarly we can carry out integer subtraction to move the pointer backwards in memory.

ptr = ptr - 1 ;
ptr -= 10 ;

The shorthand operators ++ and -- can also be used with pointers. In our continuing example
with integers the statement ptr++ ; will cause the address in ptr to be incremented by 4 and
so point to the next integer in memory and similarly ptr-- ; will cause the address in ptr to be
decremented by 4 and point to the previous integer in memory.

Note: Two pointer variables may not be added together ( it does not make any logical sense ).

char *p1, *p2 ;


p1 = p1 + p2 ; /* illegal operation */

Two pointers may however be subtracted as follows.

int *p1, *p2, array[3], count ;


p1 = array ;
p2 = &array[2] ;

count = p2 - p1 ; /* legal */
The result of such an operation is not however a pointer, it is the number of elements of the
base type of the pointer that lie between the two pointers in memory.

 Comparisons

We can compare pointers using the relational operators ==, <, and > to establish whether
two pointers point to the same location, to a lower location in memory, or to a higher location
in memory.
1. Using array notation
void puts( const char s[ ] ) /* const keyword makes string contents read only */
{
int i ;
for ( i = 0; s[i] ; i++ )
putchar( s[i] ) ;
putchar( '\n' ) ;
}

2. Using pointer notation

63 | P a g e
void puts( const char *s ) // char *const s would make pointer unalterable
{
while ( *s )
putchar( *s++ ) ;
putchar( '\n' ) ;
}

For Example :- Palindrome program using pointers.

#include <stdio.h>
int palin( char * ) ; /* Function to determine if array is a palindrome. returns 1 if
it is a palindrome, 0 otherwise */
void main( )
{
char str[30], c ;

puts( "Enter test string" ) ;


gets( str ) ;

if ( palin( str ) )
printf( "%s is a palindrome\n", str ) ;
else
printf( "%s is not a palindrome\n") ;
}

int palin ( char *str )


{
char *ptr ;

ptr = str ;
while ( *ptr )
ptr++ ; /* get length of string i.e. increment ptr while *ptr != '\0' */
ptr-- ; /* move back one from '\0' */

while ( str < ptr )


if ( *str++ != *ptr-- )
return 0 ; /* return value 0 if not a palindrome */

return 1 ; /* otherwise it is a palindrome */


}

64 | P a g e
Strings and pointers

C's standard library string handling functions use pointers to manipulate the strings. For
example the prototype for the strcmp() function found in <string.h> is

int strcmp( const char *string1, const char *string2 ) ;

where const is a C keyword which locks the variable it is associated with and prevents any
inadvertent changes to it within the function.

Strings can be initialised using pointer or array notation as follows

char *str = "Hello\n" ;


char string[] = "Hello\n" ;

in both cases the compiler allocates just sufficient storage for both strings.

Passing Arrays to Functions


Passing One Dimensional Arrays as arguments to functions

In C it is impossible to pass an entire array as an argument to a function, instead the address


of the array is passed as a parameter to the function.

The name of an array without any index is the address of the first element of the array and
hence of the whole array as it is stored contiguously. However we need to know the size of
the array in the function - either by passing an extra parameter or by using the sizeof operator.

For Example :-
void main()
{
int array[20] ;
func1( array ) ;/* passes pointer to array to func1 */
}
Since we are passing the address of the array the function will be able to manipulate the
actual data of the array in main(). This is call by reference as we are not making a copy of the
data but are instead passing its address to the function. Thus the called function is
manipulating the same data space as the calling function.

65 | P a g e
main() func1

refers to data
array x
at address 1000
data at
no data here
address 1000

In the function receiving the array the formal parameters can be declared in one of three
almost equivalent ways as follows :

 As a sized array :
func1 ( int x[10] ) {
...
}
 As an unsized array :
func1 ( int x[ ] ) {
...
}
 As an actual pointer
func1 ( int *x ) {
...
}

All three methods are identical because each tells us that in this case the address of an array
of integers is to be expected.

Note however that in cases 2 and 3 above where we specify the formal parameter as an
unsized array or simply as a pointer we cannot determine the size of the array passed in using
the sizeof operator as the compiler does not know what dimensions the array has at this point.
Instead sizeof returns the size of the pointer itself, two in the case of near pointers in a 16-bit
system but four in 32-bit systems.

For Example :- Program to calculate the average value of an array of doubles.

#include <stdio.h>
void read_array( double array[ ], int size ) ;
double mean( double array[ ], int size ) ;

void main()
{
double data[ 100 ] ;

66 | P a g e
double average ;

read_array( data, 100 ) ;


average = mean( data, 100 ) ;
}

void read_array( double array[ ], int size )


{
int i ;

for ( i = 0; i<100; i++ ) {


printf( “\nEnter data value %d : i + 1 );
scanf( “%lf”, &array[i] ;
_flushall() ;
}
}

double mean( double array[ ], int size )


{
double total = 0.0 ;
int count = size ;
while ( count-- ) // size is a local variable which we can use at will
total += array[ count ] ;
return ( total / size ) ;
}

For Example :- Program to test if a user input string is a palindrome or not.

#include <stdio.h>
int palin( char array[ ] ) ; /* Function to determine if array
is a palindrome returns 1 if it is a palindrome, 0 otherwise */
void main( )
{
char str[100] ;

puts( "Enter test string" ) ;


gets( str ) ;

if ( palin( str ) )
printf( "%s is a palindrome\n", str ) ;
else
printf( "%s is not a palindrome\n") ;
}

67 | P a g e
int palin ( char array[ ] )
{
int i = 0, j = 0 ;

while ( array[j++] ) ; /* get length of string i.e. increment j while array[j] != '\0' */
j -= 2 ; /* move back two -- gone one beyond '\0' */

for ( ; i < j ; i++, j-- )


if ( array[ i ] != array[ j ]
return 0 ; /* return value 0 if not a palindrome */

return 1 ; /* otherwise it is a palindrome */


}

An alternative way of writing the palin() function might be as follows using string
manipulation functions ( must add #include <string.h> to top of file in this case).

int palin( char array[ ] )


{
char temp[30] ;

strcpy( temp, array ) ;/* make a working copy of string */

strrev( temp ) ; /* reverse string */

if ( ! strcmp( temp, array ) ) /* compare strings –


if same strcmp returns 0 */
return 1 ;
else
return 0 ;
}

Passing Multidimensional Arrays

Function calls with multi-dimensional arrays will be the same as with single dimension arrays
as we will still only pass the address of the first element of the array.

However to declare the formal parameters to the function we need to specify all but one of
the dimensions of the array so that it may be indexed properly in the function.

For Example :-

2D array of doubles :- double x[10][20] ;

68 | P a g e
Call func1 with x a parameter :- func1( x ) ;

Declaration in func1 :- func1( double y[ ][20] ) {


...
}

The compiler must at least be informed how many columns the matrix has to index it
correctly. For example to access element y[5][3] of the array in memory the compiler might
do the following

element No = 5 * 20 + 3 = 103.

NB : Multi-dimensional arrays are stored row-wise so y[5][3] is the 4th element in the 6th row.

Since we are dealing with an array of doubles this means it must access the memory location
103 X 8 bytes from the beginning of the array.

Thus the compiler needs to know how many elements are in each row of the 2D array above.
In general the compiler needs to know all dimensions except the leftmost at the very least.

For Example :- Program to add two 2 x 2 matrices.

#include < stdio.h>

void mat_read( int mat[2][2] ) ; // Write these two functions on your own
void mat_print( int mat[2][2] ) ;

void mat_add( int mat1[ ][2], int mat2[ ][2], int mat3[ ][2] ) ;
void main()
{
int mat_a[2][2], mat_b[2][2], mat_res[2][2] ;

puts( “Enter Matrix a row-wise :-\n” );


mat_read( mat_a ) ;
puts( “\nMatrix a is :-\n” ) ;
mat_print( mat_a ) ;
puts( “Enter Matrix b row-wise” );
mat_read( mat_b ) ;
puts( “\nMatrix b is :-\n” ) ;
mat_print( mat_b ) ;

mat_add( mat_a, mat_b, mat_res ) ;

69 | P a g e
puts( “The resultant matrix is\n” ) ;
mat_print( mat_res ) ;
}

void mat_add( int mat1[ ][2], int mat2[ ][2], int mat3[ ][2] )
{
int j, k ;

for ( j = 0; j < 2; j++ )


for ( k = 0; k < 2; k++ )
mat_res[j][k] = mat1[j][k] + mat2[j][k] ;
}
Dynamic Memory Allocation

This is the means by which a program can obtain and release memory at run-time. This is
very important in the case of programs which use large data items e.g. databases which may
need to allocate variable amounts of memory or which might have finished with a particular
data block and want to release the memory used to store it for other uses.

The functions malloc() and free() form the core of C's dynamic memory allocation and are
prototyped in <malloc.h>. malloc() allocates memory from the heap i.e. unused memory
while available and free() releases memory back to the heap.

The following is the prototype for the malloc() function

void * malloc( size_t num_bytes ) ;

malloc() allocates num_bytes bytes of storage and returns a pointer to type void to the block
of memory if successful, which can be cast to whatever type is required. If malloc() is unable
to allocate the requested amount of memory it returns a NULL pointer.

For example to allocate memory for 100 characters we might do the following

#include <malloc.h>

void main()
{
char *p ;

if ( !( p = malloc( sizeof( char ) * 100 ) )


{
puts( "Out of memory" ) ;
exit(1) ;
}
}

70 | P a g e
The return type void * is automatically cast to the type of the lvalue type but to make it more
explicit we would do the following

if ( !( (char * )p = malloc( sizeof( char ) * 100 ) )


{
puts( "Out of memory" ) ;
exit(1) ;
}

To free the block of memory allocated we do the following

free ( p ) ;

Note :- There are a number of memory allocation functions included in the standard library
including calloc( ), _fmalloc( ) etc. Care must be taken to ensure that memory allocated with
a particular allocation function is released with its appropriate deallocation function, e.g.
memory allocated with malloc() is freed only with free() .

Array of Pointers

It is possible to declare arrays of pointers in C the same as any other 'type'. For example

int *x[10] ;

declares an array of ten integer pointers.

To make one of the pointers point to a variable one might do the following.

x[ 2 ] = &var ;

To access the value pointed to by x[ 2 ] we would do the following

*x[ 2 ]

which simply de-references the pointer x[ 2 ] using the * operator.

Passing this array to a function can be done by treating it the same as a normal array which
happens to be an array of elements of type int *.

For Example : -
void display( int *q[ ], int size )
{
int t ;

71 | P a g e
for ( t=0; t < size; t++ )
printf( "%d ", *q[t] ) ;
}

Note that q is actually a pointer to an array of pointers as we will see later on with multiple
indirection.

A common use of pointer arrays is to hold arrays of strings.

For Example :- A function to print error messages.

void serror( int num )


{
static char *err[] = {
"Cannot Open File\n",
"Read Error\n",
"Write Error\n" } ;

puts( err[num] );
}

Note that using an array of pointers to char initialised as above conserves space as no blank
filling characters are required as would be if we used

char err[3][30] = {
... } ;

3.2 STRINGS

In C a string is defined as a character array which is terminated by a special character, the


null character '\0', as there is no string type as such in C.

Thus the string or character array must always be defined to be one character longer than is
needed in order to cater for the '\0'.

For Example :- String S to hold 5 characters

char s[6] ;
'\0'

A string constant is simply a list of characters within double quotes e.g. "Hello" with the '\0'
character being automatically appended at the end by the compiler.

72 | P a g e
A string may be initialized as simply as follows

char s[6] = "Hello" ;

'H' 'e' 'l' 'l' 'o' '\0'

as opposed to
char s[6] = { 'H', 'e', 'l', 'l', 'o', '\0' } ;

Again the size specification may be omitted allowing the compiler to determine the size
required.

String I/O Functions

We can print out the contents of a string using printf() as we have seen already or by using
puts().

printf( "%s", s ) ;
puts( s ) ;

Strings can be read in using scanf()

scanf( "%s", s ) ;

where we do not require the familiar & as the name of an array without any index or square
braces is also the address of the array.

A string can also be read in using gets()

gets ( s ) ;

Arrays of Strings

An array of strings is in fact a two dimensional array of characters but it is more useful to
view this as an array of individual single dimension character arrays or strings.

For Example :-
char str_array[ 10 ] [ 30 ] ;

where the row index is used to access the individual row strings and where the column index
is the size of each string, thus str_array is an array of 10 strings each with a maximum size of
29 characters leaving one extra for the terminating null character.

73 | P a g e
For Example :- Program to read strings into str_array and print them out character by
character.

#include <stdio.h>

char str_array[10][30] ;

void main()
{
int i, j ;

puts("Enter ten strings\n") ;

for ( i = 0 ; i < 10; i++ ) // read in as strings so a single for


// loop suffices
{
printf( " %d : ", i + 1) ;
gets( str_array[i] ) ;
}

for ( i = 0; i < 10; i++ )//printed out as individual chars so a


{ // nested for loop structure is required
for ( j=0; str_array[i][j] != '\0' ; j++ )
putchar ( str_array[i][j] ) ;
putchar( '\n' ) ;
}
}

3.3 STRING MANIPULATION FUNCTIONS

There are some common inbuilt functions to manipulation on string in string.h file. these are
as follows:

1. strlen - string length


2. strcpy - string copy
3. strcmp - string compare
4. strups - string upper
5. strlwr - string lower
6. strcat - string concatenate

For Example :-
char s1[20] = “String1”, s2[20] = “String2” ;

74 | P a g e
int i ;

strcpy( s1, s2 ) ; /* copies s2 into s1. */

i = strcmp( s1,s2 ) ; /* compares s1 and s2. It returns zero if


s1 same as s2,-1 if s1 < s2, and +1 if s1 > s2 */

i = strlen( s1 ) ; /* returns the length of s1 */

strcat ( s1, s2 ) ; /* Concatenates s2 onto end of s1 */

The Type Definition (typedef)

C makes use of the typedef keyword to allow new data type names to be defined. No new
type is created, an existing type will now simply be recognised by another name as well. The
existing type can be one of the in-built types or a user-defined type.

Syntax : typedef type name ;

where type is C data type and name is the new name for this type.

For Example :-
typedef int INTEGER ;
INTEGER i ; // can now declare a variable of type ‘INTEGER’

typedef double * double_ptr ;


double_ptr ptr ; // no need of * here as it is part of the type

typedef struct coords {


int x, y ;
} xycoord ; // xycoord is now a type name in C
xycoord coord_var ;

The use of typedef makes program code easier to read and when used intelligently can
facilitate the porting of code to a different platform and the modification of code. For
example in a first attempt at a particular program we might decide that floating point
variables will fill our needs. This problem is trivial if we had used a typedef as follows :-

typedef float FLOATING ;

To remedy the situation we modify the user defined type as follows

75 | P a g e
typedef double FLOATING;

Enumerated Types (enum)

An enumeration is a user defined data type whose values consist of a set of named integer
constants, and are used for the sole purpose of making program code more readable.

Syntax: enum tag { value_list } [ enum_var ] ;

where tag is the name of the enumeration type, value_list is a list of valid values for the
enumeration, and where enum_var is an actual variable of this type.

For Example :-
enum colours { red, green, blue, orange } shade ;
// values red - 0, green - 1, blue - 2, orange - 3

enum day { sun = 1, mon, tue, wed = 21, thur, fri, sat } ;
enum day weekday ;
// values are 1, 2, 3, 21, 22, 23, 24

Variables declared as enumerated types are treated exactly as normal variables in use and are
converted to integers in any expressions in which they are used.

For Example :-
int i ;

shade = red ; // assign a value to shade enum variable

i = shade ; // assign value of enum to an int

shade = 3 ; // assign valid int to an enum, treat with care

Example: Use typedef to Create An Enumerated Type

typedef enum {RED, BLUE, GREEN} color;

color a,b;
a=RED;
a = RED+BLUE; //NOT ALLOWED in C
if ((a == BLUE) || (a==b)) cout<<"great";

Notice that an enumerated type is a code that associates symbols and numbers. The char type
can be thought of as an enumeration of character codes. The default code for an enumerated

76 | P a g e
type assigns the first name to the value 0 (RED), second name 1 (BLUE), third 2 (GREEN)
etc. The user can, however, override any, or all, of the default codes by specifying alternative
values.

77 | P a g e
UNIT - IV
UNIT- IV

4.1 STRUCTURES
A structure is a user defined data type in C/C++. A structure creates a data type that can be
used to group items of possibly different types into a single type.
Structures are used to represent a record. Suppose you want to keep track of your books in a
library.
You might want to track the following attributes about each book −
 Title
 Author
 Subject
 Book ID

DEFINITION AND INTIALIZATION OF STRUCTURES


‘struct’ keyword is used to create a structure. Following is an example.
struct address
{
char name[50];
char street[100];
char city[50];
char state[20];
int pin;
};
A structure variable can either be declared with structure declaration or as a separate
declaration like basic types.

// A variable declaration with structure declaration.


struct Point
{
int x, y;
} p1; // The variable p1 is declared with 'Point'
// A variable declaration like basic data types
struct Point
{
int x, y;
};
int main()
{
struct Point p1; // The variable p1 is declared like a normal variable
}
Structure members can be initialized using curly braces ‘{}’. For example, following is a
valid initialization.
struct Point

78 | P a g e
{
int x, y;
};
int main()
{
// A valid initialization. member x gets value 0 and y
// gets value 1. The order of declaration is followed.
struct Point p1 = {0, 1};
}
Structure members cannot be initialized with declaration. For example the following C
program fails in compilation.
struct Point
{
int x = 0; // COMPILER ERROR: cannot initialize members here
int y = 0; // COMPILER ERROR: cannot initialize members here
};
The reason for above error is simple, when a datatype is declared, no memory is allocated for
it. Memory is allocated only when variables are created.

ACCESSING STRUCTURES
Structure members are accessed using dot (.) operator.
struct Point
{
int x, y;
};
int main()
{
struct Point p1 = {0, 1};
// Accesing members of point p1
p1.x = 20;
printf ("x = %d, y = %d", p1.x, p1.y);
return 0;
}
4.2 NESTED STRUCTURES
A structure can be nested inside another structure. In other words, the members of a structure
can be of any other type including structure.
structure tagname_1
{
member1;
member2;
member3;
...
member n;
structure tagname_2

79 | P a g e
{
member_1;
member_2;
member_3;
...
member_n;
}, var1

} var2;

Note: Nesting of structures can be extended to any level.


To access the members of the inner structure, we write a variable name of the outer structure,
followed by a dot(.) operator, followed by the variable of the inner structure, followed by a
dot(.) operator, which is then followed by the name of the member we want to access.
var2.var1.member_1 - refers to the member_1 of structure tagname_2
var2.var1.member_2 - refers to the member_2 of structure tagname_2

4.3 ARRAY OF STRUCTURES


Like other primitive data types, we can create an array of structures.
struct Point
{
int x, y;
};
int main()
{
// Create an array of structures
struct Point arr[10];
// Access array members
arr[0].x = 10;
arr[0].y = 20;
printf("%d %d", arr[0].x, arr[0].y);
return 0;
}
Output: 10 20
4.4 STRUCTURES AND FUNCTIONS
 A structure can be passed to any function from main function or from any sub
function.
 Structure definition will be available within the function only.
 It won’t be available to other functions unless it is passed to those functions by value
or by address(reference).
 Else, we have to declare structure variable as global variable. That means, structure
variable should be declared outside the main function. So, this structure will be visible
to all the functions in a C program

80 | P a g e
PASSING STRUCTURE TO FUNCTION IN C:
It can be done in below 3 ways:
1. Passing structure to a function by value

In this program, the whole structure is passed to another function by value. It


means the whole structure is passed to another function with all members and
their values. So, this structure can be accessed from called function.

#include <stdio.h>
#include <string.h>

struct student
{
int id;
char name[20];
float percentage;
};

void func(struct student record);

int main()
{
struct student record;

record.id=1;
strcpy(record.name, "Raju");
record.percentage = 86.5;
func(record);
return 0;
}

void func(struct student record)


{
printf(" Id is: %d \n", record.id);
printf(" Name is: %s \n", record.name);
printf(" Percentage is:%f\n”, record.percentage);
}

OUTPUT:
Id is: 1
Name is: Raju
Percentage is: 86.500000

81 | P a g e
2. Passing structure to a function by address(reference)
In this program, the whole structure is passed to another function by address.
It means only the address of the structure is passed to another function. The
whole structure is not passed to another function with all members and their
values. So, this structure can be accessed from called function by its address.

#include <stdio.h>
#include <string.h>

struct student
{
int id;
char name[20];
float percentage;
};

void func(struct student *record);

int main()
{
struct student record;

record.id=1;
strcpy(record.name, "Raju");
record.percentage = 86.5;

func(&record);
return 0;
}

void func(struct student *record)


{
printf(" Id is: %d \n", record->id);
printf(" Name is: %s \n", record->name);
printf(" Percentage is: %f \n", record->percentage);
}
OUTPUT:
Id is: 1
Name is: Raju
Percentage is: 86.500000

82 | P a g e
3. No need to pass a structure – Declare structure variable as global

Structure variables also can be declared as global variables as we declare other


variables in C. So, When a structure variable is declared as global, then it is
visible to all the functions in a program. In this scenario, we don’t need to pass
the structure to any function separately.

#include <stdio.h>
#include <string.h>
struct student
{
int id;
char name[20];
float percentage;
};
struct student record; // Global declaration of structure

void structure_demo();

int main()
{
record.id=1;
strcpy(record.name, "Raju");
record.percentage = 86.5;
structure_demo();
return 0;
}

void structure_demo()
{
printf(" Id is: %d \n", record.id);
printf(" Name is: %s \n", record.name);
printf(" Percentage is: %f \n", record.percentage);
}

OUTPUT:
Id is: 1
Name is: Raju
Percentage is: 86.500000

4.5 POINTERS TO STRUCTURES


Like primitive types, we can have pointer to a structure. If we have a pointer to structure,
members are accessed using arrow ( -> ) operator.
struct Point

83 | P a g e
{
int x, y;
};

int main()
{
struct Point p1 = {1, 2};
// p2 is a pointer to structure p1
struct Point *p2 = &p1;
// Accessing structure members using structure pointer
printf("%d %d", p2->x, p2->y);
return 0;
}
Output: 1 2

4.6 SELF REFERENTIAL STRUCTURES

Self Referential structures are those structures that have one or more pointers which point to
the same type of structure, as their member.
In other words, structures pointing to the same type of structures are self-referential in nature.
Example:
struct node {
int data1;
char data2;
struct node* link;
};

int main()
{
struct node ob;
return 0;
}
In the above example ‘link’ is a pointer to a structure of type ‘node’. Hence, the structure
‘node’ is a self-referential structure with ‘link’ as the referencing pointer.
An important point to consider is that the pointer should be initialized properly before
accessing, as by default it contains garbage value.

4.7 UNIONS
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 'union' is used in
defining union and the keyword used in defining structure was 'struct'.

84 | P a g e
Union variables can be created in similar manner as structure variable

In both cases, union variables car1, car2 and union pointer variable car3 of type union car is
created.

Accessing members of a union


Again, the member of unions can be accessed in similar manner as structures.
In the above example, suppose you want to access price for union variable car1, it can be
accessed
as:

85 | P a g e
Likewise, if you want to access price for the union pointer variable car3, it can be accessed
as:

4.8 INPUT AND OUTPUT

Input to a program, means to feed some data into a program. An input can be given in the
form of a file or from the command line. C programming provides a set of built-in functions
to read the given input and feed it to the program as per requirement.
Output of a program, means to display some data on screen, printer, or in any file. C
programming provides a set of built-in functions to output the data on the computer screen as
well as to save it in text or binary files
FILES
A file represents a sequence of bytes, regardless of it being a text file or a binary file.
C programming language provides access on high level functions as well as low level (OS
level) calls to handle file on your storage devices.
Files are divided into two types
1. Stream-oriented – they are standard or high-level files. They are easier to work with than
the sytem-oriented data-files and are used more commonly.
2. System-oriented – they are low-level files.
Opening a file
Before opening any file, a file pointer needs to be established.

Syntax : Establishing a file pointer


FILE *fptr;

Where,
FILE is the structure which is defined in the header file <stdio.h>.
A file should be opened before any operation is being performed on it.
The fopen() function is being used for opening the file.

Syntax:
FILE *fopen(const char *filename, const char *mode);

In the above syntax, filename is the literal which is used for naming the files.
They can be accessed by using the following modes:

86 | P a g e
Closing a file
The fclose() function is used for closing a file.
When this function is used the file pointer is disconnected from a file.
Syntax:
int fclose(FILE *fp);
Where,fp is the file pointer that points to the file that has to be closed. An integer value is
returned which will indicate if the function was successful or not.
In addition to the fclose() function we even have the fcloseall() function which will close all
the streams which are open currently except the standard streams (stdin, stdout and stderr).
Syntax:
intfcloseall(void);
This function will flush any of the stream buffers and will return the number of streams
which are closed.
Reading a file
Following are the list of functions which are used for reading a file:

Writing a file
Following are the list of functions which are used for writing a file:

87 | P a g e
Error handling in file operations

The function ferror() is used for checking the errors in the stream.
Syntax:
int ferror(FILE *stream);
This function returns 0 if there are no errors and a value if there are some errors.
Following are the functions which are used for detecting the errors:

Accepting the command line arguments


The main() can accept two arguments
I) First argument will be an integer value that will specify the number of command-line
arguments.
II) The second argument is a full list of all the command-line arguments.
Syntax:
int main (int argc, char *argv[])
Where, argc will specify the number of arguments that are to be passed into the program from
the command-line including the name of the program. argv will contain the list of all the
arguments.
Each element of the array argv is a pointer where each pointer points to a string.In main() the
command line arguments are accepted by using the argc and argv.
Functions used for selecting a record randomly
Following are the functions which are used for selecting a record randomly:

Removing a file
The remove() function is used for erasing a file.
Syntax:
int remove (const char *filename);
All the files which are specified by the filename will be erased.
If this function is successful it will return a zero else it will return a value other than zero.
Renaming the file
The rename() function is used for renaming a file.
Syntax:
int rename(const char *oldname, const char *newname);

88 | P a g e
Where,oldname will be the pathname of the file that needs to be renamed.newname will be
the new pathname of the file.
If this function is successful it will return a zero else it will return a value other than zero.If
an error occurs neither the oldfile name nor the newfile name are renamed or changed.

STREAMS

In C, the stream is a common, logical interface to the various devices that comprise the
computer.
In its most common form, a stream is a logical interface to a file. As C defines the term "file",
it can refer to a disk file, the screen, the keyboard, a port, a file on tape, and so on. Although
files differ in form and capabilities, all streams are the same.
The stream provides a consistent interface and to the programmer one hardware device will
look much like another.
A sequence of bytes flowing into program is called input stream
A sequence of bytes flowing out of the program is called output stream
Use of Stream make I/O machine independent.
Predefined/standard streams in c are the following:
Standard Input(stdin)
Standard output(stdout)
Standard error(stderr)

When the main function of your program is invoked, it already has three predefined streams

open and available for use. These represent the “standard” input and output channels that
have been established for the process.

These streams are declared in the header file stdio.h.

Variable: FILE * stdin

The standard input stream, which is the normal source of input for the program.

Variable: FILE * stdout

The standard output stream, which is used for normal output from the program.

Variable: FILE * stderr

The standard error stream, which is used for error messages and diagnostics issued
by the program.

89 | P a g e
4.8 STANDARD LIBRARY INPUT OUTPUT FUNCTIONS

Open File - fopen and freopen

 FILE *fopen(const char *path, const char *mode)


o fopen opens the file designated by the character string path and associates it
with a stream. The mode string should begin with one of the following
sequences:
 r - open an existing file for reading, starting at the beginning of the file.
 w - truncate an existing file to zero length or create a text file for
writing, starting at the beginning of the file.
 a - open or create for writing at end of text file.
 r+ - open an existing file for reading and writing, starting at the
beginning of the file.
 w+ - truncate an existing file to zero length or create a text file for
reading and writing, starting at the beginning of the file.
 a+ - open for reading and writing at end of file or create for reading
and writing.
o The mode string may include a ‘b’ as either the second or third character to
indicate a binary file.
o The mode string may also contain other characters after the above modes,
which are used in an implementation-defined manner.
o If a file is opened for update (the + mode), an output operation may not be
followed by an input operation without flushing the buffer (fflush())) or
repositioning (fseek(), fsetpos, rewind), and an input operation may not be
followed by an output operation without flushing the buffer or repositioning
unless the input operation has reached end-of-file.
o If fopen succeeds, a FILE pointer is returned. Otherwise, NULL is returned
and errno is set.
 FILE *freopen(const char *pathname, const char *mode, FILE *stream)
o freopen behaves exactly like fopen except that it associates the newly opened
file with stream rather than creating a new stream.
o freopen is primarily used to associate a new file with one of the standard text
streams (stdin, stdout, or stderr).

Flush File Buffer - fflush

 int fflush(FILE *stream)


o fflush forces any buffered output to be written, but does not close the stream.
o If stream is a null pointer, fflush flushes all of a process' open output streams
(at least on UNIX systems)
o If the operation succeeds, fflush returns 0. Otherwise, EOF is returned and
errno is set.

90 | P a g e
Close File - fclose

 int fclose(FILE *stream)


o fclose causes any buffered output to be written (possibly using fflush) and then
closes the stream.
o Subsequent attempts to use stream in any routine other than freopen will result
in errors.
o If the operation succeeds, fclose returns 0. Otherwise, EOF is returned and
errno is set.

Check or Clear File Status - feof, ferror and clearerr

 int feof(FILE *stream)


o feof checks the end-of-file indicator for stream and returns non-zero if it is set.
o Note that even if the last character in a file has been read, an end-of-file
condition does not exist until a request is made to read the character after the
last character.
 int ferror(FILE *stream)
o ferror checks the error indicator for stream and returns non-zero if it is set.
 void clearerr(FILE *stream)
o clearerr clears the end-of-file and error indicators for stream.
o Once an end-of-file or error indicator has been set, it is not reset until clearerr
is called (with the exception that file repositioning functions clear the end-of-
file indicator.)

Read Character from File - getc, fgetc and getchar

 int fgetc(FILE *stream)


o fgetc reads the next available character from the input stream stream and
returns it as an int
 int getc(FILE *stream)
o getc is identical in function to fgetc but is usually implemented as a macro
(which means that stream may be evaluated more than once, so it should not
be an expression with side effects.)
 int getchar(void)
o getchar reads the next available character from stdin and is typically
implemented as getc(stdin) (which means it is a macro with all the problems
of getc.)
 Errors and End-Of-File
o If stream or stdin is at end-of-file or a read error occurs, these routines return
EOF (and errno is set if an error occurs.) feof or ferror must therefore be used
to distinguish between the two conditions.
o

91 | P a g e
Write Character to File - putc, fputc and putchar

 int fputc(int c, FILE *stream)


o fputc writes c to the output stream stream as an unsigned char and returns the
character as an int. If an error occurs, EOF is returned and errno is set.
 int putc(int c, FILE *stream)
o putc is identical in function to fputc but is usually implemented as a macro
(which means that stream and c may be evaluated more than once, so they
should not be expressions with side effects.)
 int putchar(int c)
o putchar writes c to stdout and is typically implemented as putc(stdout) (which
means it is a macro with all the problems of putc.)

Push Character Back into Buffer - ungetc

 int ungetc(int c, FILE *stream)


o ungetc pushes c back onto the input stream stream, so that it will be returned
by a subsequent read of stream.
o Pushed back characters are read in reverse order.
o If a file repositioning function (fseek(), fsetpos, rewind) is used, any pushed
back characters are lost.
o ungetc does not affect the contents of the file pointed to by stream
o One character of pushback is guaranteed.
o Attempts to push EOF have no effect on stream and return EOF

Read String from File - fgets and gets

 char *fgets(char *s, int n, FILE *stream)


o fgets reads characters from stream and stores them in the string pointed to by
s.
o Reading stops when a newline character is seen, end-of-file is reached or n-1
characters have been read, and '\0' is appended to s (after any newline
character.)
o If end-of-file occurs before any characters have been read, fgets returns NULL
and the contents of s are unchanged.
o If an error occurs at any time during the read operation, fgets returns NULL
and the contents of s are undefined.
o Otherwise, fgets returns s
 char *gets(char *s, FILE *stream)
o gets is similar to fgets, but is much more dangerous.
 gets does not store a newline character.
 More importantly, gets assumes that s is infinitely long, allowing
sufficiently knowledgeable programmers to worm their way inside the
program.

92 | P a g e
Write String to File - fputs and puts

 int fputs(const char *s, FILE *stream)


o fputs writes the null-terminated string s to the output stream stream.
o If an error occurs, fputs returns EOF. Otherwise, is returns a nonnegative
integer.
 int puts(const char *s)
o puts writes the null-terminated string s, followed by a newline character, to the
stdout output stream.

Read Binary Data from File - fread

 size_t fread(void *ptr, size_t siz, size_t num, FILE *stream)


o fread reads up to num objects, each siz bytes long, from input stream stream,
storing them in the memory pointed to by ptr.
o The number of objects read is returned.
o If an error occurs, zero will be returned.
o If end-of-file is reached, the value returned will be less than num (and may be
zero, in which case feof or ferror should be used to distinguish between the
two conditions.)

Write Binary Data to File - fwrite

 size_t fwrite(const void *ptr, size_t siz, size_t num, FILE *stream)
o fwrite writes up to num objects, each siz bytes long, from the memory pointed
to by ptr to the output stream stream.
o The number of objects written is returned.
o If an error occurs, zero will be returned.

Read Formatted Input - scanf, fscanf, sscanf

 int scanf(const char *format, ...)

 int fscanf(FILE *stream, const char *format, ...)


 int sscanf(const char *str, const char *format, ...)

Write Formatted Output - printf, fprintf, sprintf

int printf(const char *format, ...)

o printf writes to the stdout output stream.

int fprintf(FILE *stream, const char *format, ...)

93 | P a g e
o fprintf writes to output stream stream.

int sprintf(const char *str, const char *format, ...)

o sprintf "writes" its output to the character string str (followed by a terminating
'\0'.)

All three functions return the number of characters written (not including the terminating '\0'
for sprintf)

File Position - fgetpos, fsetpos, rewind, fseek, and ftell

 int fgetpos(FILE *stream, fpos_t *pos);


o fgetpos stores the value of the current file position indicator for stream in pos.
o pos is an implementation-defined type which may be integral or may be a
complex structure.
o If an error occurs, a non-zero value is returned and errno is set.
 int fsetpos(FILE *stream, fpos_t *pos)
o fsetpos sets the file position indicator for stream to the position indicated by
pos.
o If an error occurs, a non-zero value is returned and errno is set.
o If fsetpos succeeds, the end-of-file indicator is cleared.
 void rewind(FILE *stream)
o rewind sets the file position indicator for stream to the beginning of the file.
 int fseek(FILE *stream, long offset, int whence)
o fseek sets the file position indicator for stream. The new byte position is
obtained by adding offset to the position specified by whence:
 If whence is set to SEEK_CUR, the offset is computed from the
current position in the file.
 If whence is set to SEEK_SET, the offset is computed from the
beginning of the file.
 If whence is set to SEEK_END, the offset is computed from the end of
the file.
 SEEK_CUR, SEEK_SET, and SEEK_END are all defined in
<stdio.h>.
o fseek is usually applied to binary files.
 long ftell(FILE *stream)
o ftell returns the current file position for stream.
o For binary files, the value returned is the number of bytes from the beginning
of the file to the current file position.
o For text files, the value is implementation-defined, but is guaranteed to be
useable in fseek and 0L must represent the beginning of the file.

94 | P a g e
Alter File Buffer Size - setbuf and setvbuf

 void setvbuf(FILE *stream, char *buf, int buftype, size_t bufsize)


o setvbuf sets the type, size and location of the buffer for stream.
o The three types of buffering available are:
 _IOFBF causes I/O to be block buffered, meaning that bytes are saved
up and written when bufsize has been reached.
 _IOLBF causes I/O to be line buffered, meaning that the buffer is
written when either a newline character is saved to the buffer or when
bufsize has been reached.
 _IONBF means that no buffering is done; everything is immediately
written.
o If buf is non-null, it is assumed to be at least bufsize bytes long and will be
used instead of the automatically created buffer.
 The predefined constant BUFSIZ is the recommended value for the
buffer size.
 If buf is NULL, the stream is completely unbuffered.
o setvbuf can safely be called after a stream has been opened but before any data
are read or written.
o setvbuf returns EOF on error.
 void setbuf(FILE *stream, char *buf)
o setbuf has the same effect as
setvbuf(stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ);

Temporary File Functions - tmpfile and tmpnam

 FILE *tmpfile(void)
 tmpfile attempts to create a new file and open it using mode wb+.
 If the create and open succeed, a FILE pointer is returned.
 If the file could not be opened, NULL is returned.
 The file is automatically deleted when it is closed or when the process
terminates.
 Note that this function may create a file which is publicly readable and
writable.
 char *tmpnam(char *str)
 tmpnam generates a temporary file name which was not in use when tmpnam
was called.
 If str is non-null, the file name is copied to that buffer. str is expected to be at
least L_tmpnam characters long.
 If str is null, a static buffer is used, meaning that subsequent calls to tmpnam
may overwrite the buffer.
 Temporary file names use the path prefix P_tmpdir.
 Both L_tmpnam and P_tmpdir are defined in <stdio.h>.

95 | P a g e
 tmpnam is guaranteed to be able to generate at least TMP_MAX unique
temporary file names, where TMP_MAX must be at least 25.
 Note that there is a race condition between file name selection and file
creation.
 Note also that tmpnam does not create the file and therefore does not ensure
the file will be deleted after the program is terminated.

4.9 CHARACTER INPUT OUTPUT FUNCTIONS

The basic input/output functions are getchar, putchar, puts, scanf and printf.
The first two functions, getchar and putchar, are used to transfer single characters.
The next function puts is used to output strings, and the last two functions, scanf and printf,
permit the transfer of single characters, numerical values and strings.

Non-formatted Input-Output functions


getchar()
This is a single character input function. getchar() reads a single character from stdin - the
standard input data stream, viz. the file associated with the standard input device, which is
normally the keyboard.
putchar()
This is a single character output function. putchar() writes a single character to stdout - the
standard output data stream, viz. the file associated with the standard output device, which is
normally the console.
gets() and puts()
The standard library function gets accepts input in the form of a string. The character string
may even include whitespace characters. Each call to gets will read all the characters from the
input steam until an end of line character is encountered. The end of line character is
represented as \n and gets generated when you press the enter key. gets assigns the read string
to the variable that is passed as its parameters. gets assigns NULL when an error occurs.
The standard library function puts sends the passed string to stdout. After the output, puts
sends out a carriage return and a line feed character. This takes the cursor to the next line
automatically.
Formatted Input and Output functions
scanf()

The scanf function is used to read formatted input data. The format in which input data is to
be provided is specified by the scanf function itself as it's first parameter. The scanf function
is written as -
scanf(<control string>, &address1, &address2, . . . , &addressn);

Here, the first parameter <control string> contains a list of format specifiers indicating the
format and type of data to be read. The remaining parameters - &address1, &address2, ...,
&addressn are addresses of the variables where the read data will be stored. scanf reads the

96 | P a g e
input data as per the format specifiers and stores them (i.e., assigns them) to the
corresponding addresses. An & is pre-fixed to the variable name to denote its address.
Note that there must be the same number of format specifiers and addresses as there are input
data. For instance, in the following example:
scanf("%d %f",&x,&y);

printf()
The printf function is used to output data onto the standard output device. In general, the
printf function is written as
printf(<control string>, arg1, arg2, . . . , argn);

where the <control string> refers to a string containing required formatting information as in
scanf, and arg1, arg2, ..., argn are individual data variables whose values are to be printed.
However, unlike scanf, these data variable names are not preceded by the & symbol. This is
because printf is expected to only output the values of these variables and not their addresses.

97 | P a g e
UNIT - V
UNIT V

5.1 INTRODUCTION TO DATA STRUCTURES

Data Structure is an arrangement of data in a computer’s memory (or sometimes on a


disk).Data structures include arrays, linked lists, stacks, binary trees, and hash tables, among
others.
The figure 5.1 shows the types of data structures.

Fig 5.1 : data structures

Primitive Data Structures are the basic data structures that directly operate upon the
machine instructions. For example integers, floating point numbers, character constants,
string constants and pointers are the primitive data structures.
Non-primitive data structures are more complicated data structures and are derived from
primitive data structures. They emphasize on grouping same or different data items with
relationship between each data item. Arrays, lists and files are examples of this type.

98 | P a g e
5..2 LINEAR LIST

 One of the most simple and most used ADT is the linear list. A linear list is asequence
of n ≥ 0 elements X1,Xn called nodes having the same base type T.
 The essential structural properties of a linear list are:
o If n>0 then X1 is the first node and Xn is the last node.
o If 1 < i < n then the i-th node Xi is preceded by Xi-1 and succeeded by Xi+1.
This property expresses the basis of sequential access, i.e. if we know the
current node then we can access its predecessor and its successor.
 To define lists as an ADT we must define a set of operators. Note that each set of
operators defines a distinct ADT.

5.2.1 SINGLY LINKED LIST IMPLEMENTATION


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 as shown in Fig 2

Fig 2: Linear list

In C language, a linked list can be implemented using structure and pointers:


struct LinkedList{
int data;
struct LinkedList *next;
};
The above definition is used to create every node in the list. The data field stores the element
and the next is a pointer to store the address of the next node.

INSERTION
Insertion into a singly-linked list has three cases:
 Inserting a new node before the head (at the beginning)
In this case, a new node is inserted before the current head node. Only one next
pointer needs tobe modified (new node’s next pointer) and it can be done in two steps:
o Update the next pointer of new node, to point to the current head.
o Update head pointer to point to the new node.

99 | P a g e
 Inserting a new node after the tail (at the end of the list)
In this case, we need to modify two next pointers (last nodes next pointer and new
nodes nextpointer).
o New nodes next pointer points to NULL.

o Last nodes next pointer points to the new node.

 Inserting a new node at the middle of the list (random location)


Let us assume that we are given a position where we want to insert the new node. In
this case also, we need to modify two next pointers.

100 | P a g e
o If we want to add an element at position 3 then we stop at position 2.
That means we traverse 2 nodes and insert the new node. For
simplicity let us assume that the second node is called position node.
The new node points to the next node of the position where we want to
add this node.

o Position node’s next pointer now points to the new node.

DELETION

Similar to insertion, here we also have three cases.


Deleting the first node

First node (current head node) is removed from the list. It can be done in two steps:
o Create a temporary node which will point to the same node as that of head.

101 | P a g e
o Now, move the head nodes pointer to the next node and dispose of the
temporary node.

Deleting the last node

In this case, the last node is removed from the list. This operation is a bit trickier than
removing the first node, because the algorithm should find a node, which is previous to the
tail. It can be done in three steps:
o Traverse the list and while traversing maintain the previous node address also.
Bythe time we reach the end of the list, we will have two pointers, one
pointing to the tail node and the other pointing to the node before the tail node.

• Update previous node’s next pointer with NULL.

102 | P a g e
o Dispose of the tail node.

 Deleting an intermediate node.

In this case, the node to be removed is always located between two nodes. Head and tail links
are not updated in this case. Such a removal can be done in two steps:
o Similar to the previous case, maintain the previous node while traversing the
list.Once we find the node to be deleted, change the previous node’s next
pointer to the next pointer of the node to be deleted.

o Dispose of the current node to be deleted.

5.2.2 SEARCHING OPERATIONS ON LINEAR LIST

In order to search through the list (to find a piece of data, or an insertion point for some new
data), the only option is to traverse through the data one by one, from the start. This is known
as a linear search. More efficient search techniques (such as the binary search) cannot be
performed, as the link structure between data forces sequential access.

103 | P a g e
The step-by-step algorithm to search is, starting at the first data node, and comparing the
search key with the corresponding data in the node:
1 If the data matches, the search is complete.
2 If there is no match, move to the next node and repeat;
3 If the next reference is null, the end of the list has been reached; therefore, the data
does not exist in the list. The algorithm can now terminate

5.3 STACKS
Stack is a linear data structure which follows a particular order in which the operations are
performed. The order may be LIFO (Last In First Out) or FILO (First In Last Out).

OPERATIONS
Mainly the following basic operations are performed in the stack:

 Push: Adds an item in the stack. If the stack is full, then it is said to be an Overflow
condition.
 Pop: Removes an item from the stack. The items are popped in the reversed order in
which they are pushed. If the stack is empty, then it is said to be an Underflow
condition.
 Top: Returns top element of stack.
 isEmpty: Returns true if stack is empty, else false.

5.4 ARRAY AND LINKED REPRESENTATIONS OF STACKS


The following diagram shows the implementation of stack ADT using an array. In the array,
we add elements from left to right and use a variable to keep track of the index of the top
element.

104 | P a g e
The array storing the stack elements may become full. A push operation will then throw a full
stack exception. Similarly, if we try deleting an element from an empty stack it will throw
stack empty exception.

105 | P a g e
The other way of implementing stacks is by using Linked lists. Push operation is
implemented by inserting element at the beginning of the list. Pop operation is implemented
by deleting the node from the beginning (the header/top node).

106 | P a g e
5.5 STACK APPLICATION
 Balancing of symbols
 Infix to Postfix /Prefix conversion
 Redo-undo features at many places like editors, photoshop.
 Forward and backward feature in web browsers
 Used in many algorithms like Tower of Hanoi, tree traversals, stock span problem,
histogram problem.
 Other applications can be Backtracking, Knight tour problem, rat in a maze, N queen
problem and sudoku solver
 In Graph Algorithms like Topological Sorting and Strongly Connected Components

INFIX TO POSTFIX CONVERSION


 Infix: An infix expression is a single letter, or an operator, proceeded by one infix
string and followed by another infix string.

 Prefix: A prefix expression is a single letter, or an operator, followed by two prefix


strings.Every prefix string longer than a single variable contains an operator, first
operand and second operand.

 Postfix: A postfix expression (also called Reverse Polish Notation) is a single letter or
an operator, preceded by two postfix strings. Every postfix string longer than a single
variable contains first and second operands followed by an operator.

107 | P a g e
In infix expressions, the operator precedence is implicit unless we use parentheses. Therefore,
for the infix to postfix conversion algorithm we have to define the operator precedence (or
priority) inside the algorithm.
The table shows the precedence and their associativity (order of evaluation) among operators.

Algorithm for infix to postfix conversion:


1. Scan the infix expression from left to right.
2. If the scanned character is an operand, output it.
3. Else,
3.1If the precedence of the scanned operator is greater than the precedence of the
operator in the stack (or the stack is empty or the stack contains a ‘(‘ ), push it.
3.2 Else, Pop all the operators from the stack which are greater than or equal to in
precedence than that of the scanned operator. After doing that push the scanned

108 | P a g e
operator to the stack. (If you encounter parenthesis while popping then stop there and
push the scanned operator in the stack.)
4. If the scanned character is an ‘(‘, push it to the stack.
5. If the scanned character is an ‘)’, pop the stack and and output it until a ‘(‘ is
encountered, and discard both the parenthesis.
6. Repeat steps 2-6 until infix expression is scanned.
7. Print the output
8. Pop and output from the stack until it is not empty.

For better understanding let us trace out an example: A * B- (C + D) + E

POSTFIX EXPRESSION EVALUATION


The following algorithm describes the method used for postfix expression evaluation.
Algorithm:
1. Scan the Postfix string from left to right.
2. Initialize an empty stack.
4 Repeat steps 4 and 5 till all the characters are scanned.
5 If the scanned character is an operand, push it onto the stack.
6 If the scanned character is an operator, and if the operator is a unary operator, then
pop an element from the stack. If the operator is a binary operator, then pop two
elements from the stack. After popping the elements, apply the operator to those
popped elements. Let the result of this operation be retVal onto the stack.
7 After all characters are scanned, we will have only one element in the stack.
8 Return top of the stack as result.

Consider an example, assumethat the postfix string is 123*+5-.


Initially the stack is empty. Now, the first three characters scanned are 1, 2 and 3, which are
operands. They will be pushed into the stack in that order.

109 | P a g e
The next character scanned is “*”, which is an operator. Thus, we pop the top two elements
from the stack and perform the “*” operation with the two operands. The second operand will
be the first element that is popped.

The value of the expression (2*3) that has been evaluated (6) is pushed into the stack.

The next character scanned is “+”, which is an operator. Thus, we pop the top two elements
from the stack and perform the “+” operation with the two operands. The second operand will
be the first element that is popped.

110 | P a g e
The value of the expression (1+6) that has been evaluated (7) is pushed into the stack.

The next character scanned is “5”, which is added to the stack.

111 | P a g e
The next character scanned is “-”, which is an operator. Thus, we pop the top two elements
from the stack and perform the “-” operation with the two operands. The second operand will
be the first element that is popped.

The value of the expression(7-5) that has been evaluated(23) is pushed into the stack.

Now, since all the characters are scanned, the remaining element in the stack (there will be
only one element in the stack) will be returned. End result:
• Postfix String : 123*+5-
• Result : 2

5.14 RECURSION IMPLEMENTATION

Recursion is the process of repeating items in a self-similar way. In programming languages,


if a program allows you to call a function inside the same function, then it is called a
recursive call of the function.

112 | P a g e
Lets use factorial as an example. 5 factorial is 5x4x3x2x1 = 120 and this can be implemented
recursively.
int f(int x){

if(x == 1) return 1;// line 1

return f(x-1)*x; // line 2

void main(){

int y = f(5);// main call

// y should get 120

}
So lets watch the stack and see what happens.

main calls the function f with a value of 5, so on the stack we get f(5). Line 1 is false so we
go to line 2 which calls f(4), etc. Note that f(4) must complete before f(5) can complete. f(5)
will complete by returning 5*f(4). The stack will look like:

113 | P a g e
So at this point none of the functions have yet returned! The first to return will be f(1) which
will return 1. Then f(2) will return 2. Then f(3) will return 6. As in:

114 | P a g e
5.6 QUEUES

Queues are data structures that follow the First In First Out (FIFO) i.e. the first element that is
added to the queue is the first one to be removed.
Elements are always added to the back and removed from the front.
A waiting line is a good real-life example of a queue.

OPERATIONS

The following are the operations that are performed on queues:


 Insert(item): (also called enqueue)
It adds a new item to the tail of the queue
 Remove( ): (also called delete or dequeue)
It deletes the head item of the queue, and returns to the caller. If the queue is already
empty, this operation returns NULL
 getHead( ):
Returns the value in the head element of the queue
 getTail( ):
Returns the value in the tail element of the queue
 isEmpty( )
Returns true if the queue has no items
 size( )
Returns the number of items in the queue

115 | P a g e
ARRAY AND LINKED REPRESENTATION OF QUEUE

In the array, we add elements circularly and use two variables to keep track of the start
element and end element. Generally, front is used to indicate the start element and rear is
used to indicate the end element in the queue. The array storing the queue elements may
become full. An EnQueue operation will then throw a full queue exception. Similarly, if we
try deleting an element from an empty queue it will throw empty queue exception.

116 | P a g e
Another way of implementing queues is by using Linked lists. EnQueue operation is
implemented by inserting an element at the end of the list. DeQueue operation is
implemented by deleting an element from the beginning of the list.

117 | P a g e
118 | P a g e
119 | P a g e

You might also like