C Language Unit 1,2,3,4,5
C Language Unit 1,2,3,4,5
Computer Basics
Introduction to Computers :-
Functionalities of a computer:-
Stores the data/instructions in its memory and use them when required.
Hardware
refers to the physical components of a computer or a machine that we can see and
touch. It contains circuit board, ICs, or other electronics in a computer system. It is a
physical component that is used in different ways to build a computer or any other
machine. The Memory Devices, Processor, Central Processing Unit
, Mouse
1
all are the examples of the hardware in the computer system. On the other hand, the
screen on which you are viewing this page is the best example of the hardware, whether
you are viewing this page on the tablet, monitor, or smartphone. A computer system
would not be existing without any hardware and not able to run any software. An
example of an external hardware peripheral, a keyboard, is shown in the picture. It
allows users to give input to the computer.
Computer Software
Software
is not installed into your computer, you cannot make any document that can be
completed through MS-Word. Also, you cannot surf the Internet
or visit any website if your system has no Internet browser software. Additionally,
the browser
could not run on the computer without an operating system. The Google Chrome
, MySQL
and more are examples of software. The picture is shown below, is an example of
software, which is a picture of Google Chrome, which is an Internet software program.
2
The problem solving techniques
Problem solving is the act of defining a problem; determining the cause of the problem;
identifying, prioritizing, and selecting alternatives for a solution; and implementing a
solution.
In order to effectively manage and run a successful organization, leadership must guide
their employees and develop problem-solving techniques. Finding a suitable solution
for issues can be accomplished by following the basic four-step problem-solving
process and methodology outlined below.
Step Characteristics
3
Step Characteristics
4. Implement and follow up on Plan and implement a pilot test of the chosen
the solution alternative
Gather feedback from all affected parties
Seek acceptance or consensus by all those affected
Establish ongoing measures and monitoring
Evaluate long-term results based on final solution
1. Requirements
2. Analysis
3. Design
4. Coding
5. Testing
4
6. Maintenance
1. Requirements:-
we define the problem statement and we decide the boundaries of the problem.
Information about the problem must be stated clearly and unambiguously.
we need to understand the problem statement and gather the preliminary
requirements.
Main objective of this phase is to eliminate unimportant aspects and identify the
root problem
2. Analysis:-
3. Design:-
The software developer makes use of tools like algorithms and flowcharts to
develop the design of the program.
o Algorithm
o Flowchart
Algorith is the list of instructions in a perticular order to solve the problem
Flowcharts are used to get the pictorial representation of the algorithm
4. Coding:-
5
For effective coding some of the guide lines are to be follow:
o Use of meaningful names and labels of variables
o Simple and clear expressions
o Modularity with emphasis on making modules generalized
o Making use of comments and indenting the code properly
o Avoiding jumps in the program to transfer control
5.Testing:-
6..Maintenance:-
Updating and correction of the program for changed conditions and field
experience is accounted for in maintenance.
Maintenance becomes essential in following situations:
o Change in specification
o Change in equipment
Errors which are found during the actual execution of the program.
Structure of a C program
The structure of a C program means the specific structure to start the programming in
the C language. Without a proper structure, it becomes difficult to analyze the problem
and the solution. It also gives us a reference to write more complex programs.
6
C programming
C language
combines the power of a low-level language and a high-level language. The low-level
languages are used for system programming, while the high-level languages are used
for application programming. It is because such languages are flexible and easy to use.
Hence, C language is a widely used computer language.
It supports various operators, constructors, data structures, and loop constructs. The
features of C programming make it possible to use the language for system
programming, development of interpreters, compilers, operating systems, graphics,
general utilities, etc. C is also used to write other applications, such as databases,
compilers, word processors, and spreadsheets
Sometimes, when we begin with a new programming language, we are not aware about
the basic structure of a program. The sections of a program usually get shuffled and the
chance of omission of error rises. The structure of a language gives us a basic idea of
the order of the sections in a program. We get to know when and where to use a
particular statement, variable, function, curly braces, parentheses, etc. It also
increases our interest in that programming language.
7
Thus, the structure helps us analyze the format to write a program for the least errors. It
gives better clarity and the concept of a program.
Here, we will discuss the sections of a C program, some practical examples with
explanations, steps to compile and execute a C program.
History of C Language
Let's see the programming languages that were developed before C language.
C Identifiers
C identifiers represent the name in the C program, for example, variables, functions,
arrays, structures, unions, labels, etc. An identifier can be composed of letters such as
uppercase, lowercase letters, underscore, digits, but the starting letter should be either
an alphabet or an underscore. If the identifier is not used in the external linkage, then it
is called as an internal identifier. If the identifier is used in the external linkage, then it is
called as an external identifier.
8
o The first character of an identifier should be either an alphabet or an underscore,
and then it can be followed by any of the character, digit, or underscore.
o It should not begin with any numerical digit.
o In identifiers, both uppercase and lowercase letters are distinct. Therefore, we can
say that identifiers are case sensitive.
o Commas or blank spaces cannot be specified within an identifier.
o Keywords cannot be represented as an identifier.
o The length of the identifiers should not be more than 31 characters.
o Identifiers should be written in such a way that it is meaningful, short, and easy to
read.
Types of identifiers
o Internal identifier
o External identifier
Internal Identifier
If the identifier is not used in the external linkage, then it is known as an internal
identifier. The internal identifiers can be local variables.
External Identifier
If the identifier is used in the external linkage, then it is known as an external identifier.
The external identifiers can be function names, global variables.
9
Differences between Keyword and Identifier
Keyword Identifier
It must be written in a lowercase letter. It can be written in both lowercase and uppercase
letters.
Its meaning is pre-defined in the c Its meaning is not defined in the c compiler.
compiler.
It does not contain the underscore It can contain the underscore character.
character.
1. int main()
2. {
3. int a=10;
4. int A=20;
5. printf("Value of a is : %d",a);
6. printf("\nValue of A is :%d",A);
7. return 0;
8. }
Output
Value of a is : 10
Value of A is :20
10
The above output shows that the values of both the variables, 'a' and 'A' are different.
Therefore, we conclude that the identifiers are case sensitive.
A data type specifies the type of data that a variable can store such as integer, floating,
character, etc.
The basic data types are integer-based and floating-point based. C language supports
both signed and unsigned literals.
The memory size of the basic data types may change according to 32 or 64-bit
operating system.
Let's see the basic data types. Its size is given according to 32-bit architecture.
11
Data Types Memory Size Range
float 4 byte
double 8 byte
Constants in C
A constant is a value or variable that can't be changed in the program, for example: 10,
20, 'a', 3.4, "c programming" etc.
12
There are different types of constants in C programming.
List of Constants in C
Constant Example
.const keyword
1. #define preprocessor
1) C const keyword
Variables in C
A variable is a name of the memory location. It is used to store data. Its value can be
changed, and it can be reused many times.
13
It is a way to represent memory location through symbol so that it can be easily
identified.
1. type variable_list;
1. int a;
2. float b;
3. char c;
Here, a, b, c are variables. The int, float, char are the data types.
We can also provide values while declaring the variables as given below:
1. int a;
2. int _ab;
3. int a30;
1. int 2;
14
2. int a b;
3. int long;
Types of Variables in C
1. local variable
2. global variable
3. static variable
4. automatic variable
5. external variable
Local Variable
A variable that is declared inside the function or block is called a local variable.
1. void function1(){
2. int x=10;//local variable
3. }
Global Variable
A variable that is declared outside the function or block is called a global variable. Any
function can change the value of the global variable. It is available to all the functions.
15
Static Variable
A variable that is declared with the static keyword is called static variable.
1. void function1(){
2. int x=10;//local variable
3. static int y=10;//static variable
4. x=x+1;
5. y=y+1;
6. printf("%d,%d",x,y);
7. }
If you call this function many times, the local variable will print the same value for
each function call, e.g, 11,11,11 and so on. But the static variable will print the
incremented value in each function call, e.g. 11, 12, 13 and so on.
Automatic Variable
All variables in C that are declared inside the block, are automatic variables by default.
We can explicitly declare an automatic variable using auto keyword.
1. void main(){
2. int x=10;//local variable (also automatic)
3. auto int y=20;//automatic variable
4. }
External Variable
myfile.h
1. #include "myfile.h"
2. #include <stdio.h>
16
3. void printValue(){
4. printf("Global variable: %d", global_variable);
5. }
1. const float PI=3.14;
1. #include<stdio.h>
2. int main(){
3. const float PI=3.14;
4. printf("The value of PI is: %f",PI);
5. return 0;
6. }
Output:
An operator is simply a symbol that is used to perform operations. There can be many
types of operations like arithmetic, logical, bitwise, etc.
o Arithmetic Operators
o Relational Operators
o Shift Operators
o Logical Operators
o Bitwise Operators
o Ternary or Conditional Operators
o Assignment Operator
o Misc Operator
Precedence of Operators in C
17
The precedence of operator species that which operator will be evaluated first and next.
The associativity specifies the operator direction to be evaluated; it may be left to right
or right to left.
1. int value=10+20*10;
The value variable will contain 210 because * (multiplicative operator) is evaluated
before + (additive operator).
18
Comma , Left to right
Type Casting
Type casting is a method that converts a data type into another data type in both ways
manually and automatically. The automatic conversion is done by the compiler and
manual conversion performed by the programmer.
Type casting are 2 Types:
1. Implicit
2. Explicit
Implicit:
i) Also known as ‘automatic type conversion’. ii) Done by the compiler on its own,
without any external trigger from the user. iii) Generally takes place when in an
expression more than one data type is present. iv) In such condition type conversion
(type promotion) takes place to avoid loss of data. v)All the data types of the variables
are upgraded to the data type of the variable with largest data type.
Explicit :
This process is also called type casting and it is user defined. Here the user can type cast
the result to make it of a particular data
Next Top
19
Expression
An expression is a formula in which operands are linked to each other by the use of
operators to compute a value.
Ex: x%2 = = 0
Logical expressions :
Conditional expressions :
The precedence and associativity of C operators affect the grouping and evaluation of
operands in expressions. An operator's precedence is meaningful only if other operators
with higher or lower precedence are present. Expressions with higher-precedence
operators are evaluated first. Precedence can also be described by the word "binding."
Operators with a higher precedence are said to have tighter binding.
20
The following table summarizes the precedence and associativity (the order in which the
operands are evaluated) of C operators, listing them in order of precedence from
highest to lowest. Where several operators appear together, they have equal
precedence and are evaluated according to their associativity. The operators in the table
are described in the sections beginning with Postfix Operators. The rest of this section
gives general information about precedence and associativity.
21
Symbol 1 Type of operation Associativity
1
Operators are listed in descending order of precedence. If several operators appear on
the same line or in a group, they have equal precedence.
2
All simple and compound-assignment operators have equal precedence.
An expression can contain several operators with equal precedence. When several such
operators appear at the same level in an expression, evaluation proceeds according to
the associativity of the operator, either from right to left or from left to right. The
direction of evaluation does not affect the results of expressions that include more than
one multiplication (*), addition (+), or binary-bitwise (&, |, or ^) operator at the same
level. Order of operations is not defined by the language. The compiler is free to
evaluate such expressions in any order, if the compiler can guarantee a consistent result.
Logical operators also guarantee evaluation of their operands from left to right.
However, they evaluate the smallest number of operands needed to determine the
result of the expression. This is called "short-circuit" evaluation. Thus, some operands of
the expression may not be evaluated. For example, in the expression
x && y++
the second operand, y++, is evaluated only if x is true (nonzero). Thus, y is not
incremented if x is false (0).
22
Control Structures
C if else Statement
The if-else statement in C is used to perform the operations based on some specific
condition. The operations specified in if block are executed if and only if the given
condition is true.
o If statement
o If-else statement
o If else-if ladder
o Nested if
If Statement
The if statement is used to check some given condition and perform some operations
depending upon the correctness of that condition. It is mostly used in the scenario
where we need to perform the different operations for the different conditions. The
syntax of the if statement is given below.
1. if(expression){
2. //code to be executed
3. }
Flowchart of if statement in C
1. #include<stdio.h>
2. int main(){
3. int number=0;
4. printf("Enter a number:");
5. scanf("%d",&number);
6. if(number%2==0){
7. printf("%d is even number",number);
8. }
23
9. return 0;
10. }
Output
Enter a number:4
4 is even number
enter a number:5
Output
24
12 23 34
34 is largest
If-else Statement
The if-else statement is used to perform two operations for a single condition. The if-
else statement is an extension to the if statement using which, we can perform two
different operations, i.e., one is for the correctness of that condition, and the other is for
the incorrectness of the condition. Here, we must notice that if and else block cannot be
executed simiulteneously. Using if-else statement is always preferable since it always
invokes an otherwise case with every if condition. The syntax of the if-else statement is
given below.
if(expression){
25
Let's see the simple example to check whether a number is even or odd using if-else
statement in C language.
1. #include<stdio.h>
2. int main(){
3. int number=0;
4. printf("enter a number:");
5. scanf("%d",&number);
6. if(number%2==0){
7. printf("%d is even number",number);
8. }
9. else{
10. printf("%d is odd number",number);
11. }
12. return 0;
13. }
Output
enter a number:4
4 is even number
enter a number:5
5 is odd number
26
12. {
13. printf("Sorry ... you can't vote");
14. }
15. }
Output
The if-else-if ladder statement is an extension to the if-else statement. It is used in the
scenario where there are multiple cases to be performed for different conditions. In if-
else-if ladder statement, if a condition is true then the statements defined in the if block
will be executed, otherwise if some other condition is true then the statements defined
in the else-if block will be executed, at the last if none of the condition is true then the
statements defined in the else block will be executed. There are multiple else-if blocks
possible. It is similar to the switch case statement where the default is executed instead
of else block if none of the cases is matched.
1. if(condition1){
2. //code to be executed if condition1 is true
3. }else if(condition2){
4. //code to be executed if condition2 is true
5. }
6. else if(condition3){
7. //code to be executed if condition3 is true
8. }
9. ...
10. else{
11. //code to be executed if all the conditions are false
12. }
27
The example of an if-else-if statement in C language is given below.
1. #include<stdio.h>
2. int main(){
3. int number=0;
4. printf("enter a number:");
5. scanf("%d",&number);
6. if(number==10){
7. printf("number is equals to 10");
8. }
9. else if(number==50){
10. printf("number is equal to 50");
11. }
12. else if(number==100){
13. printf("number is equal to 100");
14. }
15. else{
16. printf("number is not equal to 10, 50 or 100");
17. }
18. return 0;
19. }
28
Output
enter a number:4
number is not equal to 10, 50 or 100
enter a number:50
number is equal to 50
Program to calculate the grade of the student according to the specified marks.
1. #include <stdio.h>
2. int main()
3. {
4. int marks;
5. printf("Enter your marks?");
6. scanf("%d",&marks);
7. if(marks > 85 && marks <= 100)
8. {
9. printf("Congrats ! you scored grade A ...");
10. }
11. else if (marks > 60 && marks <= 85)
12. {
13. printf("You scored grade B + ...");
14. }
15. else if (marks > 40 && marks <= 60)
16. {
17. printf("You scored grade B ...");
18. }
19. else if (marks > 30 && marks <= 40)
20. {
21. printf("You scored grade C ...");
22. }
23. else
24. {
25. printf("Sorry you are fail ...");
26. }
27. }
29
The syntax of switch statement in c language is given below:
1. switch(expression){
2. case value1:
3. //code to be executed;
4. break; //optional
5. case value2:
6. //code to be executed;
7. break; //optional
8. ......
9.
10. default:
11. code to be executed if all cases are not matched;
12. }
3) The case value can be used only inside the switch statement.
4) The break statement in switch case is not must. It is optional. If there is no break
statement found in the case, all the cases will be executed present after the matched
case. It is known as fall through the state of C switch statement.
Let's try to understand it by the examples. We are assuming that there are following
variables.
1. int x,y,z;
2. char a,b;
3. float f;
30
Flowchart of switch statement in C
First, the integer expression specified in the switch statement is evaluated. This value is
then matched one by one with the constant values given in the different cases. If a
match is found, then all the statements specified in that case are executed along with
the all the cases present after that case including the default statement. No two cases
can have similar values. If the matched case contains a break statement, then all the
cases present after that will be skipped, and the control comes out of the switch.
Otherwise, all the cases following the matched case will be executed.
1. #include<stdio.h>
2. int main(){
3. int number=0;
4. printf("enter a number:");
5. scanf("%d",&number);
6. switch(number){
7. case 10:
8. printf("number is equals to 10");
31
9. break;
10. case 50:
11. printf("number is equal to 50");
12. break;
13. case 100:
14. printf("number is equal to 100");
15. break;
16. default:
17. printf("number is not equal to 10, 50 or 100");
18. }
19. return 0;
20. }
Output
enter a number:4
number is not equal to 10, 50 or 100
enter a number:50
number is equal to 50
32
15. }
16.
17. }
Output
hi
In C language, the switch statement is fall through; it means if you don't use a break
statement in the switch case, all the cases after the matching case will be executed.
Let's try to understand the fall through state of switch statement by the example given
below.
1. #include<stdio.h>
2. int main(){
3. int number=0;
4.
5. printf("enter a number:");
6. scanf("%d",&number);
7.
8. switch(number){
9. case 10:
10. printf("number is equal to 10\n");
11. case 50:
12. printf("number is equal to 50\n");
13. case 100:
14. printf("number is equal to 100\n");
15. default:
16. printf("number is not equal to 10, 50 or 100");
17. }
18. return 0;
19. }
Output
33
enter a number:10
number is equal to 10
number is equal to 50
number is equal to 100
number is not equal to 10, 50 or 100
Output
enter a number:50
number is equal to 50
number is equal to 100
number is not equal to 10, 50 or 100
We can use as many switch statement as we want inside a switch statement. Such type
of statements is called nested switch case statements. Consider the following example.
1. #include <stdio.h>
2. int main () {
3.
4. int i = 10;
5. int j = 20;
6.
7. switch(i) {
8.
9. case 10:
10. printf("the value of i evaluated in outer switch: %d\n",i);
11. case 20:
12. switch(j) {
13. case 20:
14. printf("The value of j evaluated in nested switch: %d\n",j);
15. }
16. }
17.
18. printf("Exact value of i is : %d\n", i );
19. printf("Exact value of j is : %d\n", j );
34
20.
21. return 0;
22. }
Output
35
Unit -2
Array
An array is defined as the collection of similar type of data items stored at contiguous
memory locations. Arrays are the derived data type in C programming language which
can store the primitive type of data such as int, char, double, float, etc. It also has the
capability to store the collection of derived data types, such as pointers, structure, etc.
The array is the simplest data structure where each data element can be randomly
accessed by using its index number.
C array is beneficial if you have to store similar elements. For example, if we want to
store the marks of a student in 6 subjects, then we don't need to define different
variables for the marks in the different subject. Instead of that, we can define an array
which can store the marks in each subject at the contiguous memory locations.
By using the array, we can access the elements easily. Only a few lines of code are
required to access the elements of the array.
Properties of Array
o Each element of an array is of same data type and carries the same size, i.e., int =
4 bytes.
o Elements of the array are stored at contiguous memory locations where the first
element is stored at the smallest memory location.
o Elements of the array can be randomly accessed since we can calculate the
address of each element of the array with the given base address and the size of
the data element.
Advantage of C Array
2) Ease of traversing: By using the for loop, we can retrieve the elements of an array
easily.
3) Ease of sorting: To sort the elements of the array, we need a few lines of code only.
36
4) Random Access: We can access any element randomly using the array.
Disadvantage of C Array
1) Fixed Size: Whatever size, we define at the time of declaration of the array, we can't
exceed the limit. So, it doesn't grow the size dynamically like LinkedList which we will
learn later.
Declaration of C Array
data_type array_name[array_size];
1. int marks[5];
Here, int is the data_type, marks are the array_name, and 5 is the array_size.
Initialization of C Array
The simplest way to initialize an array is by using the index of each element. We can
initialize each element of the array by using the index. Consider the following example.
1. marks[0]=80;//initialization of array
2. marks[1]=60;
3. marks[2]=70;
4. marks[3]=85;
5. marks[4]=75;
C array example
1. #include<stdio.h>
37
2. int main(){
3. int i=0;
4. int marks[5];//declaration of array
5. marks[0]=80;//initialization of array
6. marks[1]=60;
7. marks[2]=70;
8. marks[3]=85;
9. marks[4]=75;
10. //traversal of array
11. for(i=0;i<5;i++){
12. printf("%d \n",marks[i]);
13. }//end of for loop
14. return 0;
15. }
Output
80
60
70
85
75
We can initialize the c array at the time of declaration. Let's see the code.
int marks[5]={20,30,40,50,60};
In such case, there is no requirement to define the size. So it may also be written as
the following code.
1. int marks[]={20,30,40,50,60};
38
Two Dimensional Array in C
1. data_type array_name[rows][columns];
1. int twodimen[4][3];
Initialization of 2D Array in C
In the 1D array, we don't need to specify the size of the array if the declaration and
initialization are being done simultaneously. However, this will not work with 2D arrays.
We will have to define at least the second dimension of the array. The two-dimensional
array can be declared and defined in the following way.
1. int arr[4][3]={{1,2,3},{2,3,4},{3,4,5},{4,5,6}};
39
10. }//end of i
11. return 0;
12. }
Output
arr[0][0] = 1
arr[0][1] = 2
arr[0][2] = 3
arr[1][0] = 2
arr[1][1] = 3
arr[1][2] = 4
arr[2][0] = 3
arr[2][1] = 4
arr[2][2] = 5
arr[3][0] = 4
arr[3][1] = 5
arr[3][2] = 6
40
18. {
19. printf("%d\t",arr[i][j]);
20. }
21. }
22. }
Output
Enter a[0][0]: 56
Enter a[0][1]: 10
Enter a[0][2]: 30
Enter a[1][0]: 34
Enter a[1][1]: 21
Enter a[1][2]: 34
Enter a[2][0]: 45
Enter a[2][1]: 56
Enter a[2][2]: 78
56 10 30
34 21 34
45 56 78
C Strings
1. By char array
2. By string literal
41
Let's see the example of declaring string by char array in C language.
1. char ch[10]={'j', 'a', 'v', 'a', 't', 'p', 'o', 'i', 'n', 't', '\0'};
As we know, array index starts from 0, so it will be represented as in the figure given
below.OOPs Concepts in Java
While declaring string, size is not mandatory. So we can write the above code as given
below:
1. char ch[]={'j', 'a', 'v', 'a', 't', 'p', 'o', 'i', 'n', 't', '\0'};
We can also define the string by the string literal in C language. For example:
1. char ch[]="javatpoint";
In such case, '\0' will be appended at the end of the string by the compiler.
Character Array in Java is an Array that holds character data types values. In Java
programming, unlike C, a character array is different from a string array, and neither a
string nor a character array can be terminated by the NUL character.
The Java language uses UTF-16 representation in a character array, string, and
StringBuffer classes.
The Character arrays are very advantageous in Java. They are very efficient and faster.
Also, the data can be manipulated without any allocations.
42
Java Strings are immutable means we can not change their internal state once they are
created. However, char arrays allow us to manipulate after the creation. Even data
structures List and Set are also acceptable.
Three-Dimensional Array
int x[2][3][4] =
{
{ {0,1,2,3}, {4,5,6,7}, {8,9,10,11} },
{ {12,13,14,15}, {16,17,18,19}, {20,21,22,23} }
};
Accessing elements in Three-Dimensional Arrays: Accessing elements in Three-
Dimensional Arrays is also similar to that of Two-Dimensional Arrays. The difference is
we have to use three loops instead of two loops for one additional dimension in
43
Three-dimensional Arrays.
CPP
// Array
#include<iostream>
int main()
int x[2][3][2] =
};
44
{
<< endl;
return 0;
Output:
Element at x[0][0][0] = 0
Element at x[0][0][1] = 1
Element at x[0][1][0] = 2
Element at x[0][1][1] = 3
45
Element at x[0][2][0] = 4
Element at x[0][2][1] = 5
Element at x[1][0][0] = 6
Element at x[1][0][1] = 7
Element at x[1][1][0] = 8
Element at x[1][1][1] = 9
Element at x[1][2][0] = 10
Element at x[1][2][1] = 11
In similar ways, we can create arrays with any number of dimensions. However, the
complexity also increases as the number of dimensions increases.
The most used multidimensional array is the Two-Dimensional Array.
1) strlen( ) Function :
Example: int n;
n = strlen(st);
• This will return the length of the string 9 which is assigned to an integer variable n.
• Note that the null character “\0‟ available at the end of a string is not counted.
2) strcpy( ) Function :
strcpy( ) function copies contents of one string into another string. Syntax for strcpy
function is given below.
46
Syntax: char * strcpy (char * destination, const char * source);
Example:
If destination string length is less than source string, entire source string value won’t be
copied into destination string.
For example, consider destination string length is 20 and source string length is 30.
Then, only 20 characters from source string will be copied into destination string and
remaining 10 characters won’t be copied and will be truncated.
strcpy(city, “BANGALORE”) ;
This will assign the string “BANGALORE” to the character variable city.
3) strcat( ) Function :
47
Example :
#include <stdio.h>
#include <string.h>
int main( )
Output :
48
Target string = welcome to
4) Strncat() function :
Syntax : char * strncat ( char * destination, const char * source, size_t num );
Example :
strncat ( str2, str1, 3 ); – First 3 characters of str1 is concatenated at the end of str2.
strncat ( str1, str2, 3 ); - First 3 characters of str2 is concatenated at the end of str1.
#include <stdio.h>
#include <string.h>
int main( )
49
printf ( "”\n Target string after strncat( ) = %s”, target ) ;
Output :
5) strcmp( ) Function :
strcmp( ) function in C compares two given strings and returns zero if they are same. If
length of string1 < string2, it returns < 0 value. If length of string1 > string2, it returns >
0 value.
strcmp( ) function is case sensitive. i.e., “A” and “a” are treated as different characters.
Example :
strcmp(city, town);
This will return an integer value “-10‟ which is the difference in the ASCII values of the
first mismatching letters “D‟ and “N‟.
* Note that the integer value obtained as the difference may be assigned to an integer
variable as follows:
int n;
n = strcmp(city, town);
6) strcmpi() function :
50
strcmpi( ) function in C is same as strcmp() function. But, strcmpi( ) function is not case
sensitive. i.e., “A” and “a” are treated as same characters. Whereas, strcmp() function
treats “A” and “a” as different characters.
• strcmpi() function is non standard function which may not available in standard library.
• Both functions compare two given strings and returns zero if they are same.
• If length of string1 < string2, it returns < 0 value. If length of string1 > string2, it
returns > 0 value.
strcmp( ) function is case sensitive. i.e., “A” and “a” are treated as different characters.
Example :
7) strlwr() function :
strlwr() function is non standard function which may not available in standard library in
C.
Program : In this program, string ”MODIFY This String To LOwer” is converted into
lower case using strlwr( ) function and result is displayed as “modify this string to lower”.
#include<stdio.h>
#include<string.h>
int main()
return 0;
51
}
Output :
8) strupr() function :
strupr() function is non standard function which may not available in standard library in
C.
Program : In this program, string ”Modify This String To Upper” is converted into
uppercase using strupr( ) function and result is displayed as “MODIFY THIS STRING TO
UPPER”.
#include<stdio.h>
#include<string.h>
int main()
printf(“%s\n”, strupr(str));
return 0;
Output :
9) strrev() function :
52
strrev() function is non standard function which may not available in standard library in
C.
Example :
strrev(name)= ltf
Program : In below program, string “Hello” is reversed using strrev( ) function and
output is displayed as “olleH”.
#include<stdio.h>
#include<string.h>
int main()
return 0;
Output :
strchr() function returns pointer to the first occurrence of the character in a given string.
53
Program : In this program, strchr( ) function is used to locate first occurrence of the
character ‘i’ in the string ”This is a string ”. Character ‘i’ is located at position 3 and
pointer is returned at first occurrence of the character ‘i’.
#include <stdio.h>
#include <string.h>
int main ()
char *p;
p = strchr (string,'i');
return 0;
Output :
strstr( ) function returns pointer to the first occurrence of the string in a given string.
Program : In this program, strstr( ) function is used to locate first occurrence of the
string “test” in the string ”This is a test string for testing”. Pointer is returned at first
occurrence of the string “test”.
54
#include <stdio.h>
#include <string.h>
int main( )
char *p;
if(p)
printf(“string found\n” );
return 0;
Output :
String found
First occurrence of ”test” in “this is a test string for testing” is “testing string for testing”
Example :
55
printf(“output=%d”, atoi(“123”)+atoi(“234”));
Example :
printf(“output=%d”, atol(“486384”)-atol(“112233”));
Example :
printf(“%1f”,atof(“3.1412”)*5*5);
15) itoa(),ltoa(),ultoa() :
These functions take three arguments, the numeric value, target string address in which
the value to be stored and radix value. Finally returns the target string address, so that
function-call can be used as argument/expression.
Example :
Char temp[50];
Printf(“output=%s”, itoa(45,temp,2));
56
Output : 101101
# include<stdio.h>
# include<conio.h>
# include<string.h>
main( )
int count = 0, i;
clrscr( );
gets(st);
switch(st [i ])
case ‘A’:
case ‘E’:
case ‘I’:
case ‘O’:
case ‘U’:
case ‘a’:
case ‘e’:
case ‘I’:
57
case ‘o’:
case ‘u’:
count ++;
break;
getch( );
• When this program is executed, the user has to enter the sentence.
• Note that gets( ) function is used to read the sentence because the string has white
spaces between the words.
• Note that a count++ statement is given only once to execute it for the cases in the
switch statement.
Output :
This is a book
Functions
In c, we can divide a large program into the basic building blocks known as function.
The function contains the set of programming statements enclosed by {}. A function can
be called multiple times to provide reusability and modularity to the C program. In other
words, we can say that the collection of functions creates a program. The function is also
known as procedureor subroutinein other programming languages.
Advantage of functions in C
58
There are the following advantages of C functions.
o By using functions, we can avoid rewriting same logic/code again and again in a
program.
o We can call C functions any number of times in a program and from any place in
a program.
o We can track a large C program easily when it is divided into multiple functions.
o Reusability is the main achievement of C functions.
o However, Function calling is always a overhead in a C program.
Function Aspects
o Function call Function can be called from anywhere in the program. The
parameter list must not differ in function calling and function declaration. We
must pass the same number of functions as it is declared in the function
declaration.
SN C function Syntax
aspects
59
2 Function call function_name (argument_list)
Types of Functions
1. Library Functions: are the functions which are declared in the C header files such
as scanf(), printf(), gets(), puts(), ceil(), floor() etc.
2. User-defined functions: are the functions which are created by the C
programmer, so that he/she can use it many times. It reduces the complexity of a
big program and optimizes the code.
Return Value
A C function may or may not return a value from the function. If you don't have to
return any value from the function, use void for the return type.
Let's see a simple example of C function that doesn't return any value from the function.
60
Example without return value:
1. void hello(){
2. printf("hello c");
3. }
If you want to return any value from the function, you need to use any data type such as
int, long, char, etc. The return type depends on the value to be returned from the
function.
Let's see a simple example of C function that returns int value from the function.
1. int get(){
2. return 10;
3. }
In the above example, we have to return 10 as a value, so the return type is int. If you
want to return floating-point value (e.g., 10.2, 3.1, 54.5, etc), you need to use float as the
return type of the method.
1. float get(){
2. return 10.2;
3. }
Now, you need to call the function, to get the value of the function.
categories of functions in C
Depending on whether arguments are present or not and whether a value is returned or
not, functions are categorized into −
61
Example
#include<stdio.h>
main (){
void sum ();
clrscr ();
sum ();
getch ();
}
void sum (){
int a,b,c;
printf("enter 2 numbers:\n");
scanf ("%d%d", &a, &b);
c = a+b;
printf("sum = %d",c);
}
Output
Enter 2 numbers:
3
5
Sum=8
Functions without arguments and with return values
62
Example
#include<stdio.h>
main (){
int sum ();
int c;
c= sum ();
printf(“sum = %d”,c);
getch ();
}
int sum (){
int a,b,c;
printf(“enter 2 numbers”);
scanf (“%d%d”, &a, &b);
c = a+b;
return c;
}
Output
Enter two numbers 10 20
30
63
Functions with arguments and without return values
Example
#include<stdio.h>
main (){
void sum (int, int );
int a,b;
printf("enter 2 numbers");
scanf("%d%d", &a,&b);
sum (a,b);
getch ();
}
void sum ( int a, int b){
int c;
c= a+b;
printf (“sum=%d”, c);
}
Output
Enter two numbers 10 20
Sum=30
64
Functions with arguments and with return values
Example
#include<stdio.h>
main (){
int sum ( int,int);
int a,b,c;
printf("enter 2 numbers");
scanf("%d%d", &a,&b);
c= sum (a,b);
printf ("sum=%d", c);
getch ();
}
int sum ( int a, int b ){
int c;
c= a+b;
return c;
}
Output
Enter two numbers 10 20
65
Sum=30
C Function Parameters
Parameters and Arguments
Parameters are specified after the function name, inside the parentheses. You can add as
many parameters as you want, just separate them with a comma:
Syntax
The following function that takes a string of characters with name as parameter. When
the function is called, we pass along a name, which is used inside the function to print
"Hello" and the name of each person.
Example
int main() {
myFunction("Liam");
myFunction("Jenny");
myFunction("Anja");
return 0;
}
// Hello Liam
// Hello Jenny
// Hello Anja
66
When a parameter is passed to the function, it is called an argument. So, from the
example above: name is a parameter, while Liam, Jenny and Anja are arguments.
Multiple Parameters
Inside the function, you can add as many parameters as you want:
Example
int main() {
myFunction("Liam", 3);
myFunction("Jenny", 14);
myFunction("Anja", 30);
return 0;
}
Return Values
The void keyword, used in the previous examples, indicates that the function should not
return a value. If you want the function to return a value, you can use a data type (such
as int or float, etc.) instead of void, and use the return keyword inside the function:
Example
int myFunction(int x) {
return 5 + x;
}
int main() {
printf("Result is: %d", myFunction(3));
67
return 0;
}
// Outputs 8 (5 + 3)
Parameter Passing in C
When a function gets executed in the program, the execution control is transferred from
calling-function to called function and executes function definition, and finally comes
back to the calling function. When the execution control is transferred from calling-
function to called-function it may carry one or number of data values. These data values
Parameters are the data values that are passed from calling function to called
function.
Actual Parameters
Formal Parameters
The actual parameters are the parameters that are speficified in calling function.
The formal parameters are the parameters that are declared at called function. When a
function gets executed, the copy of actual parameter values are copied into formal
parameters.
In C Programming Language, there are two methods to pass parameters from calling
Call by Value
Call by Reference
Call by Value
68
In call by value parameter passing method, the copy of actual parameter values are
copied to formal parameters and these formal parameters are used in called
function. The changes made on the formal parameters does not effect the values of
actual parameters. That means, after the execution control comes back to the calling
function, the actual parameter values remains same. For example consider the following
program...
Example Program
#include<stdio.h>
#include<conio.h>
void main(){
int num1, num2 ;
void swap(int,int) ; // function declaration
clrscr() ;
num1 = 10 ;
num2 = 20 ;
69
temp = a ;
a=b;
b = temp ;
}
Output:
In the above example program, the variables num1 and num2 are called actual
parameters and the variables a and b are called formal parameters. The value
of num1 is copied into a and the value of num2 is copied into b. The changes made on
variables a and b does not effect the values of num1 and num2.
Call by Reference
In Call by Reference parameter passing method, the memory location address of the
actual parameters is copied to formal parameters. This address is used to access the
That means in call by reference parameter passing method, the address of the actual
parameters is passed to the called function and is recieved by the formal parameters
(pointers). Whenever we use these formal parameters in called function, they directly
access the memory locations of actual parameters. So the changes made on the
formal parameters effects the values of actual parameters. For example consider the
following program...
70
Example Program
#include<stdio.h>
#include<conio.h>
void main(){
int num1, num2 ;
void swap(int *,int *) ; // function declaration
clrscr() ;
num1 = 10 ;
num2 = 20 ;
Output:
71
In the above example program, the addresses of variables num1 and num2 are copied
to pointer variables a and b. The changes made on the pointer variables a and b in
called function effects the values of actual parameters num1 and num2 in calling
function.
Scope rules
Scope of an identifier is the part of the program where the identifier may directly be
accessible. In C, all identifiers are lexically(or statically) scoped. C scope rules can be
covered under the following two categories.
There are basically 4 scope rules:
Scope Meaning
Scope of a Identifier starts at the beginning of the file and ends at the
end of the file. It refers to only those Identifiers that are declared
outside of all functions. The Identifiers of File scope are visible all over
File Scope the file Identifiers having file scope are global
Scope of a Identifier begins at opening of the block / ‘{‘ and ends at the
Block Scope end of the block / ‘}’. Identifiers with block scope are local to their block
Function
Prototype Identifiers declared in function prototype are visible within the
Scope prototype
Function Function scope begins at the opening of the function and ends with the
72
Scope Meaning
{
declaration statements;
}
where the braces limit the block. The characteristic of a block is its nesting structure.
Delimiters mark the starting and end of the block. In 'C' language, the braces { } act as
73
delimiters, while ALGOL uses begin and end. Delimiter ensures that the block is
independent of one another or is nested inside the other. The nesting property is
sometimes referred to as a block structure.
The execution of the above block structure program using stack can be shown in the
following way −
Storage Classes in C
Storage classes in C are used to determine the lifetime, visibility, memory location, and
initial value of a variable. There are four types of storage classes in C
74
Automatic
External
Static
Register
Automatic
The visibility of the automatic variables is limited to the block in which they are defined.
The scope of the automatic variables is limited to the block in which they are defined.
The memory assigned to automatic variables gets freed upon exiting from the block.
Example 1
#include <stdio.h>
int main()
int a; //auto
char b;
float c;
return 0;
75
Output:
Static
The variables defined as static specifier can hold their value between the multiple
function calls.
Static local variables are visible only to the function or the block in which they are
defined.
A same static variable can be declared many times but can be assigned at only one time.
The visibility of the static global variable is limited to the file in which it has declared.
Example 1
#include<stdio.h>
static char c;
static int i;
static float f;
void main ()
Output:
0 0 0.000000 (null)
76
Register
The variables defined as the register is allocated the memory into the CPU registers
depending upon the size of the memory remaining in the CPU.
We can not dereference the register variables, i.e., we can not use &operator for the
register variable.
The access time of the register variables is faster than the automatic variables.
The register keyword is used for the variable which should be stored in the CPU register.
However, it is compiler?s choice whether or not; the variables can be stored in the
register.
We can store pointers into the register, i.e., a register can store the address of a variable.
Static variables can not be stored into the register since we can not use more than one
storage specifier for the same variable.
Example 1
#include <stdio.h>
int main()
register int a; // variable a is allocated memory in the CPU register. The initial default
value of a is 0.
printf("%d",a);
Output:
77
External
The external storage class is used to tell the compiler that the variable defined as extern
is declared with an external linkage elsewhere in the program.
The variables declared as extern are not allocated any memory. It is only declaration and
intended to specify that the variable is declared elsewhere in the program.
We can only initialize the extern variable globally, i.e., we can not initialize the external
variable within any block or method.
An external variable can be declared many times but can be initialized at only once.
If a variable is declared as external then the compiler searches for that variable to be
initialized somewhere in the program which may be extern or static. If it is not, then the
compiler will show an error.
Example 1
#include <stdio.h>
int main()
extern int a;
printf("%d",a);
Output
78
Recursion in C
Recursion is the process which comes into existence when a function calls a copy of
itself to work on a smaller problem. Any function which calls itself is called recursive
function, and such function calls are called recursive calls. Recursion involves several
numbers of recursive calls. However, it is important to impose a termination condition of
recursion. Recursion code is shorter than iterative code however it is difficult to
understand.
Recursion cannot be applied to all the problem, but it is more useful for the tasks that
can be defined in terms of similar subtasks. For Example, recursion may be applied to
sorting, searching, and traversal problems.
Generally, iterative solutions are more efficient than recursion since function call is
always overhead. Any problem that can be solved recursively, can also be solved
iteratively. However, some problems are best suited to be solved by the recursion, for
example, tower of Hanoi, Fibonacci series, factorial finding, etc.
1. #include <stdio.h>
2. int fact (int);
3. int main()
4. {
5. int n,f;
6. printf("Enter the number whose factorial you want to calculate?");
7. scanf("%d",&n);
8. f = fact(n);
9. printf("factorial = %d",f);
10. }
11. int fact(int n)
12. {
13. if (n==0)
14. {
15. return 0;
16. }
17. else if ( n == 1)
18. {
79
19. return 1;
20. }
21. else
22. {
23. return n*fact(n-1);
24. }
25. }
Output
Enter the number whose factorial you want to calculate?5
factorial = 120
We can understand the above program of the recursive method call by the figure given
below:
Recursive Function
A recursive function performs the tasks by dividing it into the subtasks. There is a
termination condition defined in the function which is satisfied by some specific subtask.
After this, the recursion stops and the final result is returned from the function.
The case at which the function doesn't recur is called the base case whereas the
instances where the function keeps calling itself to perform a subtask, is called the
recursive case. All the recursive functions can be written using this format.
80
1. if (test_for_base)
2. {
3. return some_value;
4. }
5. else if (test_for_another_base)
6. {
7. return some_another_value;
8. }
9. else
10. {
11. // Statements;
13. }
Example of recursion in C
Let's see an example to find the nth term of the Fibonacci series.
1. #include<stdio.h>
2. int fibonacci(int);
3. void main ()
4. {
5. int n,f;
7. scanf("%d",&n);
81
8. f = fibonacci(n);
9. printf("%d",f);
10. }
12. {
13. if (n==0)
14. {
15. return 0;
16. }
17. else if (n == 1)
18. {
19. return 1;
20. }
21. else
22. {
24. }
25. }
Output
144
82
Memory allocation of Recursive method
Each recursive call creates a new copy of that method in the memory. Once some data is
returned by the method, the copy is removed from the memory. Since all the variables
and other stuff declared inside function get stored in the stack, therefore a separate
stack is maintained at each recursive call. Once the value is returned from the
corresponding function, the stack gets destroyed. Recursion involves so much
complexity in resolving and tracking the values at each recursive call. Therefore we need
to maintain the stack and track the values of the variables defined in the stack.
Let us consider the following example to understand the memory allocation of the
recursive functions.
2. {
3. if(n == 0)
5. else
6. {
7. printf("%d",n);
9. }
10. }
Explanation
Let us examine this recursive function for n = 4. First, all the stacks are maintained which
prints the corresponding value of n until n becomes 0, Once the termination condition is
reached, the stacks get destroyed one by one by returning 0 to its calling stack.
Consider the following image for more information regarding the stack trace for the
recursive functions.
83
Unit-3
C Pointers
The pointer in C language is a variable which stores the address of another variable. This
variable can be of type int, char, array, function, or any other pointer. The size of the
pointer depends on the architecture. However, in 32-bit architecture the size of a
pointer is 2 byte.
Consider the following example to define a pointer which stores the address of an
integer.
1. int n = 10;
2. int* p = &n; // Variable p of type pointer is pointing to the address of the variable n of t
ype integer.
Declaring a pointer
The pointer in c language can be declared using * (asterisk symbol). It is also known as
indirection pointer used to dereference a pointer.
Pointer Example
An example of using pointers to print the address and value is given below.
istory of Java
84
As you can see in the above figure, pointer variable stores the address of number
variable, i.e., fff4. The value of number variable is 50. But the address of pointer variable
p is aaa3.
By the help of * (indirection operator), we can print the value of pointer variable p.
Let's see the pointer example as explained for the above figure.
1. #include<stdio.h>
2. int main(){
3. int number=50;
4. int *p;
5. p=&number;//stores the address of number variable
6. printf("Address of p variable is %x \n",p); // p contains the address of the number theref
ore printing p gives the address of number.
7. printf("Value of p variable is %d \n",*p); // As we know that * is used to dereference a po
inter therefore if we print *p, we will get the value stored at the address contained by p.
8. return 0;
9. }
Output
Pointer to array
1. int arr[10];
2. int *p[10]=&arr; // Variable p of type pointer is pointing to the address of an integer arr
ay arr.
Pointer to a function
1. void show (int);
2. void(*p)(int) = &display; // Pointer p is pointing to the address of a function
Pointer to structure
1. struct st {
85
2. int i;
3. float f;
4. }ref;
5. struct st *p = &ref;
Advantage of pointer
1) Pointer reduces the code and improves the performance, it is used to retrieving
strings, trees, etc. and used with arrays, structures, and functions.
3) It makes you able to access any memory location in the computer's memory.
Usage of pointer
In c language, we can dynamically allocate memory using malloc() and calloc() functions
where the pointer is used.
Pointers in c language are widely used in arrays, functions, and structures. It reduces the
code and improves the performance.
The address of operator '&' returns the address of a variable. But, we need to use %u to
display the address of a variable.
1. #include<stdio.h>
2. int main(){
3. int number=50;
86
4. printf("value of number is %d, address of number is %u",number,&number);
5. return 0;
6. }
Output
1. #include<stdio.h>
2. void main ()
3. {
4. int a = 10;
5. int *p;
6. int **pp;
7. p = &a; // pointer p is pointing to the address of a
8. pp = &p; // pointer pp is a double pointer pointing to the address of pointer p
9. printf("address of a: %x\n",p); // Address of a will be printed
10. printf("address of p: %x\n",pp); // Address of p will be printed
87
11. printf("value stored at p: %d\n",*p); // value stoted at the address contained by p i.e. 1
0 will be printed
12. printf("value stored at pp: %d\n",**pp); // value stored at the address contained by th
e pointer stoyred at pp
13. }
Output
address of a: d26a8734
address of p: d26a8738
value stored at p: 10
value stored at pp: 10
void pointer in C
Till now, we have studied that the address assigned to a pointer should be of the same
type as specified in the pointer declaration. For example, if we declare the int pointer,
then this int pointer cannot point to the float variable or some other type of variable,
i.e., it can point to only int type variable. To overcome this problem, we use a pointer to
void. A pointer to void means a generic pointer that can point to any data type. We can
assign the address of any data type to the void pointer, and a void pointer can be
assigned to any type of the pointer without performing any explicit typecasting.
1. void *ptr;
In the above declaration, the void is the type of the pointer, and 'ptr' is the name of the
pointer.
Till now, we have seen that in C programming, we can pass the variables as an argument
to a function. We cannot pass the function as an argument to another function. But we
can pass the reference of a function as a parameter by using a function pointer. This
process is known as call by reference as the function parameter is passed as a pointer
88
that holds the address of arguments. If any change made by the function using pointers,
then it will also reflect the changes at the address of the passed variable.
Therefore, C programming allows you to create a pointer pointing to the function, which
can be further passed as an argument to the function. We can create a function pointer
as follows:
1. (type) (*pointer_name)(parameter);
In the above syntax, the type is the variable type which is returned by the
function, *pointer_name is the function pointer, and the parameter is the list of the
argument passed to the function.
A function pointer can also point to another function, or we can say that it holds the
address of another function.
In the above case, we have declared a function named as 'add'. We have also declared
the function pointer (*a) which returns the floating-type value, and contains two
parameters of integer type. Now, we can assign the address of add() function to the 'a'
pointer as both are having the same return type(float), and the same type of arguments.
Now, 'a' is a pointer pointing to the add() function. We can call the add() function by
using the pointer, i.e., 'a'. Let's see how we can do that:
1. a(2, 3);
The above statement calls the add() function by using pointer 'a', and two parameters
are passed in 'a', i.e., 2 and 3.
Let's see a simple example of how we can pass the function pointer as a
parameter.
89
1. void display(void (*p)())
2. {
3. for(int i=1;i<=5;i++)
4. {
5. p(i);
6. }
7. }
8. void print_numbers(int num)
9. {
10. cout<<num;
11. }
12. int main()
13. {
14. void (*p)(int); // void function pointer declaration
15. printf("The values are :");
16. display(print_numbers);
17. return 0;
18. }
Output
90
Pass By Address:
We've seen Pass By Value and Pass By Reference. If you declare a formal parameter of a
function as a pointer type, you are passing that parameter by its address. The pointer is
copied, but not the data it points to. So, Pass By Address offers another method of
allowing us to change the original argument of a function (like with Pass By Reference).
Don't pass in the argument itself -- just pass in its address.
Example:
void SquareByAddress(int * n)
{ *n = (*n) * (*n); }
int main()
{
int num = 4;
cout << "Original = " << num << '\n';
SquareByAddress(&num);
cout << "New value = " << num << '\n';
}
pointers and two-dimensional array
Pointer is a variable that stores the address of another variable.
Features
Pointer saves the memory space.
91
With the help of pointers, the memory is accessed efficiently, i.e., memory is
allocated and deallocated dynamically.
#include<stdio.h>
main ( ){
92
int a[3] [3], i,j;
int *p;
clrscr ( );
printf ("Enter elements of 2D array");
for (i=0; i<3; i++){
for (j=0; j<3; j++){
scanf ("%d", &a[i] [j]);
}
}
p = &a[0] [0];
printf ("elements of 2d array are");
for (i=0; i<3; i++){
for (j=0; j<3; j++){
printf ("%d \t", *(p+i*3+j));
}
printf ("\n");
}
getch ( );
}
Output
When the above program is executed, it produces the following result −
93
Dynamic Memory Allocation in C using malloc(), calloc(), free() and
realloc()
Since C is a structured language, it has some fixed rules for programming. One of them
includes changing the size of an array. An array is a collection of items stored at
contiguous memory locations.
As it can be seen that the length (size) of the array above made is 9. But what if there is
a requirement to change this length (size). For Example,
If there is a situation where only 5 elements are needed to be entered in this array. In
this case, the remaining 4 indices are just wasting memory in this array. So there is a
requirement to lessen the length (size) of the array from 9 to 5.
Take another situation. In this, there is an array of 9 elements with all 9 indices filled.
But there is a need to enter 3 more elements in this array. In this case, 3 indices more
are required. So the length (size) of the array needs to be changed from 9 to 12.
This procedure is referred to as Dynamic Memory Allocation in C.
Therefore, C Dynamic Memory Allocation can be defined as a procedure in which the
size of a data structure (like Array) is changed during the runtime.
C provides some functions to achieve these tasks. There are 4 library functions provided
by C defined under <stdlib.h> header file to facilitate dynamic memory allocation in C
programming. They are:
1. malloc()
2. calloc()
3. free()
4. realloc()
Let’s look at each of them in greater detail.
C malloc() method
94
which can be cast into a pointer of any form. It doesn’t Initialize memory at execution
time so that it has initialized each block with the default garbage value initially.
Syntax:
ptr = (cast-type*) malloc(byte-size)
For Example:
ptr = (int*) malloc(100 * sizeof(int));
Since the size of int is 4 bytes, this statement will allocate 400 bytes of memory. And, the
pointer ptr holds the address of the first byte in the allocated memory.
#include <stdlib.h>
int main()
int* ptr;
int n, i;
scanf("%d",&n);
95
// allocated by malloc or not
if (ptr == NULL) {
exit(0);
else {
ptr[i] = i + 1;
return 0;
}Output:
96
calloc() method
1. “calloc” or “contiguous allocation” method in C is used to dynamically allocate the
specified number of blocks of memory of the specified type. it is very much similar to
malloc() but has two different points and these are:
2. It initializes each block with a default value ‘0’.
3. It has two parameters or arguments as compare to malloc().
Syntax:
ptr = (cast-type*)calloc(n, element-size);
here, n is the no. of elements and element-size is the size of each element.
For Example:
ptr = (float*) calloc(25, sizeof(float));
This statement allocates contiguous space in memory for 25 elements each with the size of
the float.
#include <stdio.h>
#include <stdlib.h>
int main()
int* ptr;
97
int n, i;
n = 5;
if (ptr == NULL) {
exit(0);
else {
ptr[i] = i + 1;
98
printf("%d, ", ptr[i]);
return 0;
}
Output:
Enter number of elements: 5
Memory successfully allocated using calloc.
The elements of the array are: 1, 2, 3, 4, 5,
C free() method
Example:
#include <stdio.h>
99
#include <stdlib.h>
int main()
int n, i;
n = 5;
exit(0);
else {
100
printf("Memory successfully allocated using malloc.\n");
free(ptr);
free(ptr1);
return 0;
}
Output:
Enter number of elements: 5
Memory successfully allocated using malloc.
Malloc Memory successfully freed.
101
where ptr is reallocated with new size 'newSize'.
#include <stdio.h>
#include <stdlib.h>
int main()
int* ptr;
int n, i;
n = 5;
102
ptr = (int*)calloc(n, sizeof(int));
if (ptr == NULL) {
exit(0);
else {
ptr[i] = i + 1;
n = 10;
103
// Dynamically re-allocate memory using realloc()
ptr[i] = i + 1;
free(ptr);
return 0;
Output:
Enter number of elements: 5
Memory successfully allocated using calloc.
The elements of the array are: 1, 2, 3, 4, 5,
Enter the new size of the array: 10
Memory successfully re-allocated using realloc.
104
The elements of the array are: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
Array of pointers
Before we understand the concept of arrays of pointers, let us consider the following
example, which uses an array of 3 integers −
#include <stdio.h>
int main () {
return 0;
}
When the above code is compiled and executed, it produces the following result −
Value of var[0] = 10
Value of var[1] = 100
Value of var[2] = 200
There may be a situation when we want to maintain an array, which can store pointers
to an int or char or any other data type available. Following is the declaration of an
array of pointers to an integer −
int *ptr[MAX];
It declares ptr as an array of MAX integer pointers. Thus, each element in ptr, holds a
pointer to an int value. The following example uses three integers, which are stored in
an array of pointers, as follows −
#include <stdio.h>
int main () {
105
int var[] = {10, 100, 200};
int i, *ptr[MAX];
return 0;
}
When the above code is compiled and executed, it produces the following result −
Value of var[0] = 10
Value of var[1] = 100
Value of var[2] = 200
You can also use an array of pointers to character to store a list of strings as follows −
#include <stdio.h>
int main () {
char *names[] = {
"Zara Ali",
"Hina Ali",
"Nuha Ali",
"Sara Ali"
};
int i = 0;
return 0;
106
}
When the above code is compiled and executed, it produces the following result −
Value of names[0] = Zara Ali
Value of names[1] = Hina Ali
Value of names[2] = Nuha Ali
Value of names[3] = Sara Ali
The arguments passed from command line are called command line arguments. These
arguments are handled by main() function.
To support command line argument, you need to change the structure of main()
function as given below.
Here, argc counts the number of arguments. It counts the file name as the first
argument.
The argv[] contains the total number of arguments. The first argument is the file name
always.
Example
Let's see the example of command line arguments where we are passing one argument
with file name.
1. #include <stdio.h>
2. void main(int argc, char *argv[] ) {
3.
4. printf("Program name is: %s\n", argv[0]);
5.
6. if(argc < 2){
7. printf("No argument passed through command line.\n");
8. }
9. else{
107
10. printf("First argument is: %s\n", argv[1]);
11. }
12. }
1. ./program hello
1. program.exe hello
Output:
Output:
But if you pass many arguments within double quote, all arguments will be treated as a
single argument only.
Output:
You can write your program to print all the arguments. In this program, we are printing
only argv[1], that is why it is printing only one argument.
108
Structure
The ,struct keyword is used to define the structure. Let's see the syntax to define the
structure in c.
1. struct structure_name
2. {
3. data_type member1;
4. data_type member2;
5. .
6. .
7. data_type memeberN;
8. };
1. struct employee
2. { int id;
3. char name[20];
4. float salary;
5. };
The following image shows the memory allocation of the structure employee that is
defined in the above example.
109
Here, struct is the keyword; employee is the name of the structure; id, name,
and salary are the members or fields of the structure. Let's understand it by the diagram
given below:
We can declare a variable for the structure so that we can access the member of the
structure easily. There are two ways to declare structure variable:
1st way:
Let's see the example to declare the structure variable by struct keyword. It should be
declared within the main function.
struct employee
1. { int id;
2. char name[50];
3. float salary;
4. };
110
The variables e1 and e2 can be used to access the values stored in the structure. Here,
e1 and e2 can be treated in the same way as the objects in C++
2nd way:
Let's see another way to declare variable at the time of defining the structure.
1. struct employee
2. { int id;
3. char name[50];
4. float salary;
5. }e1,e2;
If number of variables are not fixed, use the 1st approach. It provides you the flexibility
to declare the structure variable many times.
If no. of variables are fixed, use 2nd approach. It saves your code to declare a variable in
main() function.
Let's see the code to access the id member of p1 variable by. (member) operator.
1. p1.id
C Structure example
1. #include<stdio.h>
2. #include <string.h>
3. struct employee
4. { int id;
111
5. char name[50];
6. }e1; //declaring e1 variable for structure
7. int main( )
8. {
9. //store first employee information
10. e1.id=101;
11. strcpy(e1.name, "Sonoo Jaiswal");//copying string into char array
12. //printing first employee information
13. printf( "employee 1 id : %d\n", e1.id);
14. printf( "employee 1 name : %s\n", e1.name);
15. return 0;
16. }
Output:
employee 1 id : 101
employee 1 name : Sonoo Jaiswal
Array of Structures
112
Let's see an example of an array of structures that stores information of 5 students and
prints it.
1. #include<stdio.h>
2. #include <string.h>
3. struct student{
4. int rollno;
5. char name[10];
6. };
7. int main(){
8. int i;
9. struct student st[5];
10. printf("Enter Records of 5 students");
11. for(i=0;i<5;i++){
12. printf("\nEnter Rollno:");
13. scanf("%d",&st[i].rollno);
14. printf("\nEnter Name:");
15. scanf("%s",&st[i].name);
16. }
17. printf("\nStudent Information List:");
18. for(i=0;i<5;i++){
19. printf("\nRollno:%d, Name:%s",st[i].rollno,st[i].name);
20. }
21. return 0;
22. }
Output:
113
Enter Rollno:5
Enter Name:Sarfraz
Below is the demonstration of a program that uses the concept of the array within a
structure. The program displays the record of a student comprising the roll
number, grade, and marks secured in various subjects. The marks in various subjects
have been stored under an array called marks. The whole record is stored under a
structure called a candidate.\
#include <stdio.h>
struct candidate {
114
int roll_no;
char grade;
float marks[4];
};
printf("Marks secured:\n");
int i;
115
int len = sizeof(a1.marks) / sizeof(float);
printf("Subject %d : %.2f\n",
i + 1, a1.marks[i]);
// Driver Code
int main()
// Initialize a structure
struct candidate A
116
// Function to display structure
display(A);
return 0;
Output:
Roll number : 1
Grade : A
Marks secured:
Subject 1 : 98.50
Subject 2 : 77.00
Subject 3 : 89.00
Subject 4 : 78.50
Nested Structure
C provides us the feature of nesting one structure within another structure by using
which, complex data types are created. For example, we may need to store the address
of an entity employee in a structure. The attribute address may also have the subparts
as street number, city, state, and pin code. Hence, to store the address of the employee,
we need to store the address of the employee into a separate structure and nest the
structure address into the structure employee. Consider the following program.
1. #include<stdio.h>
2. struct address
3. {
4. char city[20];
117
5. int pin;
6. char phone[14];
7. };
8. struct employee
9. {
10. char name[20];
11. struct address add;
12. };
13. void main ()
14. {
15. struct employee emp;
16. printf("Enter employee information?\n");
17. scanf("%s %s %d %s",emp.name,emp.add.city, &emp.add.pin, emp.add.phone);
18. printf("Printing the employee information....\n");
19. printf("name: %s\nCity: %s\nPincode: %d\nPhone: %s",emp.name,emp.add.city,emp.a
dd.pin,emp.add.phone);
20. }
Output
Arun
Delhi
110001
1234567890
name: Arun
City: Delhi
Pincode: 110001
118
Phone: 1234567890
Self-referential structure:
The self-referential structure is a structure that points to the same type of structure. It
contains one or more pointers that ultimately point to the same structure.
119
Union in C
Union is a user-defined data type, but unlike structures, they share the same memory
location.
1. struct abc
2. {
3. int a;
4. char b;
5. }
The above code is the user-defined structure that consists of two members, i.e., 'a' of
type int and 'b' of type character. When we check the addresses of 'a' and 'b', we found
that their addresses are different. Therefore, we conclude that the members in the
structure do not share the same memory location.
When we define the union, then we found that union is defined in the same way as the
structure is defined but the difference is that union keyword is used for defining the
union data type, whereas the struct keyword is used for defining the structure. The
union contains the data members, i.e., 'a' and 'b', when we check the addresses of both
120
the variables then we found that both have the same addresses. It means that the union
members share the same memory location.
1. union abc
2. {
3. int a;
4. char b;
5. }var;
6. int main()
7. {
8. var.a = 66;
9. printf("\n a = %d", var.a);
10. printf("\n b = %d", var.b);
11. }
The size of the union is based on the size of the largest member of the union.
1. union abc{
2. int a;
3. char b;
4. float c;
5. double d;
6. };
7. int main()
8. {
9. printf("Size of union abc is %d", sizeof(union abc));
10. return 0;
11. }
We can access the members of the union through pointers by using the (->) arrow
operator.
121
Let's understand through an example.
#include <stdio.h>
1. union abc
2. {
3. int a;
4. char b;
5. };
6. int main()
7. {
8. union abc *ptr; // pointer variable declaration
9. union abc var;
10. var.a= 90;
11. ptr = &var;
12. printf("The value of a is : %d", ptr->a);
13. return 0;
14. }
Difference between Structure and Union
Let's summarize the above discussed topic about the Struct and Union in the form of a
table that highlight the differences between structure and union
Struct Union
The struct keyword is used to define a The union keyword is used to define
structure. union.
When the variables are declared in a When the variable is declared in the
structure, the compiler allocates memory to union, the compiler allocates memory to
each variables member. The size of a the largest size variable member. The size
structure is equal or greater to the sum of of a union is equal to the size of its
122
the sizes of each data member. largest data member size.
Each variable member occupied a unique Variables members share the memory
memory space. space of the largest size variable.
Changing the value of a member will not Changing the value of one member will
affect other variables members. also affect other variables members.
Each variable member will be assessed at a Only one variable member will be
time. assessed at a time.
We can initialize multiple variables of a In union, only the first data member can
structure at a time. be initialized.
All variable members store some value at Exactly only one data member stores a
any point in the program. value at any particular instance in the
program.
The structure allows initializing multiple Union allows initializing only one variable
variable members at once. member at once.
It is used to store different data type values. It is used for storing one at a time from
different data type values.
It allows accessing and retrieving any data It allows accessing and retrieving any one
member at a time. data member at a time.
typedef in C
. It behaves similarly as we define the alias for the commands. In short, we can say that
this keyword is used to redefine the name of an already existing variable.
Syntax of typedef
123
In the above syntax, 'existing_name' is the name of an already existing variable while
'alias name' is another name given to the existing variable.
For example, suppose we want to create a variable of type unsigned int, then it
becomes a tedious task if we want to declare multiple variables of this type. To
overcome the problem, we use a typedef keyword.
In the above statements, we have declared the unit variable of type unsigned int by
using a typedef keyword.
Now, we can create the variables of type unsigned int by writing the following
statement:
1. unit a, b;
instead of writing:
1. unsigned int a, b;
Till now, we have observed that the typedef keyword provides a nice shortcut by
providing an alternative name for an already existing variable. This keyword is useful
when we are dealing with the long data type especially, structure declarations.
1. #include <stdio.h>
2. int main()
3. {
4. typedef unsigned int unit;
5. unit i,j;
6. i=10;
7. j=20;
8. printf("Value of i is :%d",i);
9. printf("\nValue of j is :%d",j);
10. return 0;
11. }
124
Output
Value of i is :10
Value of j is :20
Bit Fields in C
In C, we can specify size (in bits) of structure and union members. The idea is to use
memory efficiently when we know that the value of a field or group of fields will never
exceed a limit or is within a small range.
For example, consider the following declaration of date without the use of bit fields.
C
Output:
The enum in C is also known as the enumerated type. It is a user-defined data type that
consists of integer values, and it provides meaningful names to these values. The use of
enum in C makes the program easy to understand and maintain. The enum is defined by
using the enum keyword.
In the above declaration, we define the enum named as flag containing 'N' integer
constants. The default value of integer_const1 is 0, integer_const2 is 1, and so on. We
can also change the default value of the integer constants at the time of the declaration.
125
For example:
#include <stdio.h>
struct date {
unsigned int d;
unsigned int m;
unsigned int y;
};
int main()
sizeof(struct date));
1. enum fruits{
2. mango=2,
3. apple=1,
126
4. strawberry=5,
5. papaya=7,
6. };
1. enum status{false,true};
In the above statement, we have declared the 's' variable of type status.
1. enum status{false,true} s;
In this case, the default value of false will be equal to 0, and the value of true will be
equal to 1.
#include <stdio.h>
2. int main()
3. {
4. enum weekdays w; // variable declaration of weekdays type
5. w=Monday; // assigning value of Monday to w.
6. printf("The value of w is %d",w);
7. return 0;
127
8. }
In the above code, we create an enum type named as weekdays, and it contains the
name of all the seven days. We have assigned 1 value to the Sunday, and all other
names will be given a value as the previous value plus one.
Output
FILES
File Handling in C
File handling in C enables us to create, update, read, and delete the files stored on the
local file system through our C program. The following operations can be performed on
a file.
128
There are many functions in the C library to open, read, write, search and close the file. A
list of file functions are given below:
Files is collection of records (or) it is a place on hard disk, where data is stored
permanently.
Types of Files
There are two types of files in C language which are as follows −
Text file
Binary File
Text File
It contains alphabets and numbers which are easily understood by human beings.
129
An error in a text file can be eliminated when seen.
In text file, the text and characters will store one char per byte.
For example, the integer value 4567 will occupy 2 bytes in memory, but, it will
occupy 5 bytes in text file.
The data format is usually line-oriented. Here, each line is a separate command.
Binary file
It contains 1’s and 0’s, which are easily understood by computers.
The error in a binary file corrupts the file and is not easy to detect.
In binary file, the integer value 1245 will occupy 2 bytes in memory and in file.
For example, an MP3 file can be produced by a sound recorder or audio editor,
and it can be played in a music player.
We must open a file before it can be read, write, or update. The fopen() function is used
to open a file. The syntax of the fopen() is given below.
o The file name (string). If the file is stored at some specific location, then we must
mention the path at which the file is stored. For example, a file name can be
like "c://some_folder/some_file.ext".
o The mode in which the file is to be opened. It is a string.
130
o Then, it loads the file from the disk and place it into the buffer. The buffer is used
to provide efficiency for the read operations.
o It sets up a character pointer which points to the first character of the file.
1. #include<stdio.h>
2. void main( )
3. {
4. FILE *fp ;
5. char ch ;
6. fp = fopen("file_handle.c","r") ;
7. while ( 1 )
8. {
9. ch = fgetc ( fp ) ;
10. if ( ch == EOF )
11. break ;
12. printf("%c",ch) ;
13. }
14. fclose (fp ) ;
15. }
Output
#include;
void main( )
{
FILE *fp; // file pointer
char ch;
fp = fopen("file_handle.c","r");
while ( 1 )
{
ch = fgetc ( fp ); //Each character of the file is read and stored in the character file.
if ( ch == EOF )
break;
131
printf("%c",ch);
}
fclose (fp );
}
The fclose() function is used to close a file. The file must be closed after performing all
the operations on it. The syntax of fclose() function is given below:
C File management
A File can be used to store a large volume of persistent data. Like many other languages
‘C’ provides following file management functions,
1. Creation of a file
2. Opening a file
3. Reading a file
4. Writing to a file
5. Closing a file
Following are the most important file management functions available in ‘C,’
function purpose
132
function purpose
FILE *fp;
fp = fopen ("file_name", "mode");
In the above syntax, the file is a data structure which is defined in the standard library.
If the file is not present on the system, then it is created and then opened.
If a file is already present on the system, then it is directly opened using this
function.
Whenever you open or create a file, you have to specify what you are going to do with
the file. A file in ‘C’ programming can be created or opened for reading/writing
purposes. A mode is used to specify whether you want to open a file for any of the
below-given purposes. Following are the different types of modes in ‘C’ programming
which can be used while working with a file.
File
Description
Mode
133
File
Description
Mode
Open a file for reading. If a file is in reading mode, then no data is deleted if a file
r
is already present on a system.
Open a file for writing. If a file is in writing mode, then a new file is created if a file
w doesn’t exist at all. If a file is already present on a system, then all the data inside
the file is truncated, and it is opened for writing purposes.
Open a file in
a append mode. If a file is in append mode, then the file is opened. The content
within the file doesn’t change.
In the given syntax, the filename and the mode are specified as strings hence they must
always be enclosed within double quotes.
Example:
#include <stdio.h>
int main() {
FILE *fp;
fp = fopen ("data.txt", "w");
}
Output:
File is created in the same folder where you have saved your code.
134
You can specify the path where you want to create your file
#include <stdio.h>
int main() {
FILE *fp;
fp = fopen ("D://data.txt", "w");
}
‘C’ provides the fclose function to perform file closing operation. The syntax of fclose is
as follows,
fclose (file_pointer);
Example:
FILE *fp;
fp = fopen ("data.txt", "r");
fclose (fp);
The fclose function takes a file pointer as an argument. The file associated with the file
pointer is then closed with the help of fclose function. It returns 0 if close was successful
and EOF (end of file) if there is an error has occurred while file closing.
After closing the file, the same file pointer can also be used with other files.
In ‘C’ programming, files are automatically close when the program is terminated.
Closing a file manually by writing fclose function is a good programming practice.
Writing to a File
In C, when you write to a file, newline characters ‘\n’ must be explicitly added.
135
The stdio library offers the necessary functions to write to a file:
fputc() Function:
#include <stdio.h>
int main() {
int i;
FILE * fptr;
char fn[50];
char str[] = "Guru99 Rocks\n";
fptr = fopen("fputc_test.txt", "w"); // "w" defines "writing mode"
for (i = 0; str[i] != '\n'; i++) {
/* write to file using fputc() function */
fputc(str[i], fptr);
}
fclose(fptr);
return 0;
}
Output:
The above program writes a single character into the fputc_test.txt file until it reaches
the next line symbol “\n” which indicates that the sentence was successfully written. The
process is to take each character of the array and write it into the file.
136
1. In the above program, we have created and opened a file called fputc_test.txt in a
write mode and declare our string which will be written into the file.
2. We do a character by character write operation using for loop and put each
character in our file until the “\n” character is encountered then the file is closed
using the fclose function.
fputs () Function:
#include <stdio.h>
int main() {
FILE * fp;
fp = fopen("fputs_test.txt", "w+");
fputs("This is Guru99 Tutorial on fputs,", fp);
fputs("We don't need to use for loop\n", fp);
fputs("Easier than fputc function\n", fp);
fclose(fp);
return (0);
}
OUTPUT:
137
1. In the above program, we have created and opened a file called fputs_test.txt in a
write mode.
2. After we do a write operation using fputs() function by writing three different
strings
3. Then the file is closed using the fclose function.
fprintf()Function:
#include <stdio.h>
int main() {
FILE *fptr;
fptr = fopen("fprintf_test.txt", "w"); // "w" defines "writing mode"
/* write to file */
fprintf(fptr, "Learning C with Guru99\n");
fclose(fptr);
return 0;
}
OUTPUT:
1. In the above program we have created and opened a file called fprintf_test.txt in
a write mode.
2. After a write operation is performed using fprintf() function by writing a string,
then the file is closed using the fclose function.
fgetc(file_pointer): It returns the next character from the file pointed to by the
file pointer. When the end of the file has been reached, the EOF is sent back.
138
fgets(buffer, n, file_pointer): It reads n-1 characters from the file and stores the
string in a buffer in which the NULL character ‘\0’ is appended as the last
character.
fscanf(file_pointer, conversion_specifiers, variable_adresses): It is used to
parse and analyze data. It reads characters from the file and assigns the input to a
list of variable pointers variable_adresses using conversion specifiers. Keep in
mind that as with scanf, fscanf stops reading a string when space or newline is
encountered.
#include <stdio.h>
int main() {
FILE * file_pointer;
char buffer[30], c;
fclose(file_pointer);
return 0;
}
Result:
139
----read a line----
Learning C with Guru99
1. In the above program, we have opened the file called “fprintf_test.txt” which was
previously written using fprintf() function, and it contains “Learning C with
Guru99” string. We read it using the fgets() function which reads line by line
where the buffer size must be enough to handle the entire line.
2. We reopen the file to reset the pointer file to point at the beginning of the file.
Create various strings variables to handle each word separately. Print the
variables to see their contents. The fscanf() is mainly used to extract and parse
data from a file.
3. Reopen the file to reset the pointer file to point at the beginning of the file. Read
data and print it from the file character by character using getc() function until
the EOF statement is encountered
4. After performing a reading operation file using different variants, we again closed
the file using the fclose function.
#include <stdio.h>
int main() {
FILE * fp;
char c;
printf("File Handling\n");
//open a file
fp = fopen("demo.txt", "w");
//writing operation
140
while ((c = getchar()) != EOF) {
putc(c, fp);
}
//close file
fclose(fp);
printf("Data Entered:\n");
//reading
fp = fopen("demo.txt", "r");
while ((c = getc(fp)) != EOF) {
printf("%c", c);
}
fclose(fp);
return 0;
}
Output:
141
1. In the above program we have created and opened a file called demo in a write
mode.
2. After a write operation is performed, then the file is closed using the fclose
function.
3. We have again opened a file which now contains data in a reading mode. A while
loop will execute until the eof is found. Once the end of file is found the
operation will be terminated and data will be displayed using printf function.
4. After performing a reading operation file is again closed using the fclose
function.
Summary
Note : These input and output values could be of any primitive data type.
142
Formatted input/output functions
Formatted console input/output functions are used to take one or more inputs from the
user at console and it also allows us to display one or multiple values in the output to
the user at the console.
Functions Description
While calling any of the formatted console input/output functions, we must use a
specific format specifiers in them, which allow us to read or display any value of a
specific primitive data type. Let's see what are these format specifiers.
143
Unit -4
Data Structure?
The data structure name indicates itself that organizing the data in memory. There are
many ways of organizing the data in the memory as we have already seen one of the
data structures, i.e., array in C language. Array is a collection of memory elements in
which data is stored sequentially, i.e., one after another. In other words, we can say that
array stores the elements in a continuous manner. This organization of data is done with
the help of an array of data structures. There are also other ways to organize the data in
memory. Let's see the different types of data structures.
The data structure is not any programming language like C, C++, java, etc. It is a set of
algorithms that we can use in any programming language to structure the data in the
memory.
To structure the data in memory, 'n' number of algorithms were proposed, and all these
algorithms are known as Abstract data types. These abstract data types are the set of
rules.
144
Primitive Data structure
The primitive data structures are primitive data types. The int, char, float, double, and
pointer are the primitive data structures that can hold a single value.
The arrangement of data in a sequential manner is known as a linear data structure. The
data structures used for this purpose are Arrays, Linked list, Stacks, and Queues. In these
data structures, one element is connected to only one another element in a linear form.
Time Complexity
1. int i = 1;
2. do
3. {
4. i++;
5. }while(i<=n);
145
n: Number of times the loop is to be executed.
In above scenario, loop is executed 'n' times. Therefore, time complexity of this loop is
O(n).
1. int i=1;
2. do
3. {
4. i = i*c;
5. }while(i<=n);
c: It is a constant.
1. int i=0;
146
2. do{
3. do{
4. int j =0;
5. j++;
6. }while(j<=i);
7. i++;
8. }while(i<=n-1);
In this case, in each iteration of i, inner loop is executed 'n' times. The time complexity of
a loop is equal to the number of times the innermost statement is to be executed.
1. int i=1;
147
2. do{
3. i++;
4. }while(i<=m);
5.
6. int j=1;
7. do{
8. j++;
9. }while(j<=n);
Time complexity of different loops is equal to the sum of the complexities of individual
loop.
Therefore,
Space Complexity:
o Space complexity: An algorithm's space complexity is the amount of space
required to solve a problem and produce an output. Similar to the time
complexity, space complexity is also expressed in big O notation.
Auxiliary space: The extra space required by the algorithm, excluding the input size, is
known as an auxiliary space. The space complexity considers both the spaces, i.e.,
auxiliary space, and space used by the input.
So,
148
Naïve method
Pattern matching in C− We have to find if a string is present in another string, as an
example, the string "algorithm” is present within the string "naive algorithm". If it is
found, then its location (i.e. position it is present at) is displayed. We tend to create a
function that receives 2 character arrays and returns the position if matching happens
otherwise returns -1.
The time complexity of the Naive Algorithm is O(mn), where m is the size of the pattern
to be searched and n is the size of the container string.
Pattern searching is a very crucial problem in computer science. Whenever we seek for a
string in notepad/word file or browser or database or in some information, pattern
searching algorithms are used to show the search results.
149
Algorithm
naive_algorithm(pattern, text)
Start
pat_len := pattern Size
str_len := string size
for i := 0 to (str_len - pat_len), do
for j := 0 to pat_len, do
if text[i+j] ≠ pattern[j], then
break
if j == patLen, then
display the position i, as there pattern found
End
Example
#include <stdio.h>
#include <string.h>
int main (){
char txt[] = "tutorialsPointisthebestplatformforprogrammers";
char pat[] = "a";
int M = strlen (pat);
int N = strlen (txt);
for (int i = 0; i <= N - M; i++){
int j;
for (j = 0; j < M; j++)
if (txt[i + j] != pat[j])
break;
if (j == M)
150
printf ("Pattern matches at index %d \n", i);
}
return 0;
}
Output
Pattern matches at 6
Pattern matches at 25
Pattern matches at 39
The Rabin-Karp-Algorithm:
The Rabin-Karp string matching algorithm calculates a hash value for the pattern, as well
as for each M-character subsequences of text to be compared. If the hash values are
unequal, the algorithm will determine the hash value for next M-character sequence. If
the hash values are equal, the algorithm will analyze the pattern and the M-character
sequence. In this way, there is only one comparison per text subsequence, and character
matching is only required when the hash values match.
RABIN-KARP-MATCHER (T, P, d, q)
1. n ← length [T]
2. m ← length [P]
3. h ← dm-1 mod q
4. p ← 0
5. t0 ← 0
6. for i ← 1 to m
7. do p ← (dp + P[i]) mod q
8. t0 ← (dt0+T [i]) mod q
9. for s ← 0 to n-m
10. do if p = ts
11. then if P [1.....m] = T [s+1.....s + m]
12. then "Pattern occurs with shift" s
13. If s < n-m
14. then ts+1 ← (d (ts-T [s+1]h)+T [s+m+1])mod q
151
Example: For string matching, working module q = 11, how many spurious hits does
the Rabin-Karp matcher encounters in Text T = 31415926535.......
1. T = 31415926535.......
2. P = 26
3. Here T.Length =11 so Q = 11
4. And P mod Q = 26 mod 11 = 4
5. Now find the exact match of P mod Q...
Solution:
152
Linear Search Algorithm
In this article, we will discuss the Linear Search Algorithm. Searching is the process of
finding some particular element in the list. If the element is present in the list, then the
process is called successful, and the process returns the location of that element;
otherwise, the search is called unsuccessful.
153
Two popular search methods are Linear Search and Binary Search. So, here we will
discuss the popular searching technique, i.e., Linear Search Algorithm.
Linear search is also called as sequential search algorithm. It is the simplest searching
algorithm. In Linear search, we simply traverse the list completely and match each
element of the list with the item whose location is to be found. If the match is found,
then the location of the item is returned; otherwise, the algorithm returns NULL.
It is widely used to search an element from the unordered list, i.e., the list in which items
are not sorted. The worst-case time complexity of linear search is O(n).
The steps used in the implementation of Linear Search are listed as follows -
Algorithm
1. Linear_Search(a, n, val) // 'a' is the given array, 'n' is the size of given array, 'val' is the val
ue to search
2. Step 1: set pos = -1
3. Step 2: set i = 1
4. Step 3: repeat step 4 while i <= n
5. Step 4: if a[i] == val
6. set pos = i
7. print pos
8. go to step 6
9. [end of if]
10. set ii = i + 1
11. [end of loop]
154
12. Step 5: if pos = -1
13. print "value is not present in the array "
14. [end of if]
15. Step 6: exit
To understand the working of linear search algorithm, let's take an unsorted array. It will
be easy to understand the working of linear search with an example.
Now, start from the first element and compare K with each element of the array.
The value of K, i.e., 41, is not matched with the first element of the array. So, move to
the next element. And follow the same process until the respective element is found.
155
Now, the element to be searched is found. So algorithm will return the index of the
element matched
In this article, we will discuss the Binary Search Algorithm. Searching is the process of
finding some particular element in the list. If the element is present in the list, then the
process is called successful, and the process returns the location of that element.
Otherwise, the search is called unsuccessful.
Linear Search and Binary Search are the two popular searching techniques. Here we will
discuss the Binary Search Algorithm.
Binary search is the search technique that works efficiently on sorted lists. Hence, to
search an element into some list using the binary search technique, we must ensure that
the list is sorted.
Binary search follows the divide and conquer approach in which the list is divided into
two halves, and the item is compared with the middle element of the list. If the match is
156
found then, the location of the middle element is returned. Otherwise, we search into
either of the halves depending upon the result produced through the match.
Algorithm
To understand the working of the Binary search algorithm, let's take a sorted array. It
will be easy to understand the working of Binary search with an example.
157
o Iterative method
o Recursive method
The recursive method of binary search follows the divide and conquer approach.
We have to use the below formula to calculate the mid of the array -
beg = 0
end = 8
158
Now, the element to search is found. So algorithm will return the index of the element
matched.
Sorting Algorithms
Sorting is the process of arranging the elements of an array so that they can be placed
either in ascending or descending order. For example, consider an array A = {A1, A2, A3,
A4, ?? An }, the array is called to be in ascending order if element of A are arranged like
A1 > A2 > A3 > A4 > A5 > ? > An .
Consider an array;
There are many techniques by using which, sorting can be performed. In this section of
the tutorial, we will discuss each method in detail.
Sorting Algorithms
Sorting algorithms are described in the following table along with the description.
159
In this article, we will discuss the Bubble sort Algorithm. The working procedure of
bubble sort is simplest. This article will be very helpful and interesting to students as
they might face bubble sort as a question in their examinations. So, it is important to
discuss the topic.
Bubble sort works on the repeatedly swapping of adjacent elements until they are not in
the intended order. It is called bubble sort because the movement of array elements is
just like the movement of air bubbles in the water. Bubbles in water rise up to the
surface; similarly, the array elements in bubble sort move to the end in each iteration.
Algorithm
1. begin BubbleSort(arr)
2. for all array elements
3. if arr[i] > arr[i+1]
4. swap(arr[i], arr[i+1])
5. end if
6. end for
7. return arr
8. end BubbleSort
160
To understand the working of bubble sort algorithm, let's take an unsorted array. We
are taking a short and accurate array, as we know the complexity of bubble sort is O(n2).
First Pass
Sorting will start from the initial two elements. Let compare them to check which is
greater.
Here, 32 is greater than 13 (32 > 13), so it is already sorted. Now, compare 32 with 26.
Here, 26 is smaller than 36. So, swapping is required. After swapping new array will look
like -
Here, 35 is greater than 32. So, there is no swapping required as they are already sorted.
Here, 10 is smaller than 35 that are not sorted. So, swapping is required. Now, we reach
at the end of the array. After first pass, the array will be -
161
Now, move to the second iteration.
Second Pass
Here, 10 is smaller than 32. So, swapping is required. After swapping, the array will be -
Third Pass
Here, 10 is smaller than 26. So, swapping is required. After swapping, the array will be -
162
Now, move to the fourth iteration.
Fourth pass
In this article, we will discuss the Selection sort Algorithm. The working procedure of
selection sort is also simple. This article will be very helpful and interesting to students
as they might face selection sort as a question in their examinations. So, it is important
to discuss the topic.
In selection sort, the smallest value among the unsorted elements of the array is
selected in every pass and inserted to its appropriate position into the array. It is also
the simplest algorithm. It is an in-place comparison sorting algorithm. In this algorithm,
the array is divided into two parts, first is sorted part, and another one is the unsorted
part. Initially, the sorted part of the array is empty, and unsorted part is the given array.
Sorted part is placed at the left, while the unsorted part is placed at the right.
In selection sort, the first smallest element is selected from the unsorted array and
placed at the first position. After that second smallest element is selected and placed in
the second position. The process continues until the array is entirely sorted.
The average and worst-case complexity of selection sort is O(n2), where n is the number
of items. Due to this, it is not suitable for large data sets.
Algorithm
163
1. SELECTION SORT(arr, n)
2.
3. Step 1: Repeat Steps 2 and 3 for i = 0 to n-1
4. Step 2: CALL SMALLEST(arr, i, n, pos)
5. Step 3: SWAP arr[i] with arr[pos]
6. [END OF LOOP]
7. Step 4: EXIT
8.
9. SMALLEST (arr, i, n, pos)
10. Step 1: [INITIALIZE] SET SMALL = arr[i]
11. Step 2: [INITIALIZE] SET pos = i
12. Step 3: Repeat for j = i+1 to n
13. if (SMALL > arr[j])
14. SET SMALL = arr[j]
15. SET pos = j
16. [END OF if]
17. [END OF LOOP]
18. Step 4: RETURN pos
To understand the working of the Selection sort algorithm, let's take an unsorted array.
It will be easier to understand the Selection sort via an example.
Now, for the first position in the sorted array, the entire array is to be scanned
sequentially.
At present, 12 is stored at the first position, after searching the entire array, it is found
that 8 is the smallest value.
164
So, swap 12 with 8. After the first iteration, 8 will appear at the first position in the sorted
array.
For the second position, where 29 is stored presently, we again sequentially scan the
rest of the items of unsorted array. After scanning, we find that 12 is the second lowest
element in the array that should be appeared at second position.
Now, swap 29 with 12. After the second iteration, 12 will appear at the second position
in the sorted array. So, after two iterations, the two smallest values are placed at the
beginning in a sorted way.
The same process is applied to the rest of the array elements. Now, we are showing a
pictorial representation of the entire sorting process.
In this article, we will discuss the Insertion sort Algorithm. The working procedure of
insertion sort is also simple. This article will be very helpful and interesting to students
as they might face insertion sort as a question in their examinations. So, it is important
to discuss the topic.
Insertion sort works similar to the sorting of playing cards in hands. It is assumed that
the first card is already sorted in the card game, and then we select an unsorted card. If
the selected unsorted card is greater than the first card, it will be placed at the right
side; otherwise, it will be placed at the left side. Similarly, all unsorted cards are taken
and put in their exact place.
The same approach is applied in insertion sort. The idea behind the insertion sort is that
first take one element, iterate it through the sorted array. Although it is simple to use, it
is not appropriate for large data sets as the time complexity of insertion sort in the
average case and worst case is O(n2), where n is the number of items. Insertion sort is
less efficient than the other sorting algorithms like heap sort, quick sort, merge sort, etc.
165
o Simple implementation
o Efficient for small data sets
o Adaptive, i.e., it is appropriate for data sets that are already substantially sorted.
Algorithm
The simple steps of achieving the insertion sort are listed as follows -
Step 1 - If the element is the first element, assume that it is already sorted. Return 1.
Step3 - Now, compare the key with all elements in the sorted array.
Step 4 - If the element in the sorted array is smaller than the current element, then
move to the next element. Else, shift greater elements in the array towards the right.
To understand the working of the insertion sort algorithm, let's take an unsorted array. It
will be easier to understand the insertion sort via an example.
Here, 31 is greater than 12. That means both elements are already in ascending order.
So, for now, 12 is stored in a sorted sub-array.
166
Now, move to the next two elements and compare them.
Here, 25 is smaller than 31. So, 31 is not at correct position. Now, swap 31 with 25.
Along with swapping, insertion sort will also check it with all elements in the sorted
array.
For now, the sorted array has only one element, i.e. 12. So, 25 is greater than 12. Hence,
the sorted array remains sorted after swapping.
Now, two elements in the sorted array are 12 and 25. Move forward to the next
elements that are 31 and 8.
167
So, swap them too.
Now, the sorted array has three items that are 8, 12 and 25. Move to the next items that
are 31 and 32.
Hence, they are already sorted. Now, the sorted array includes 8, 12, 25 and 31.
168
Now, the array is completely sorted.
In this article, we will discuss the Quicksort Algorithm. The working procedure of
Quicksort is also simple. This article will be very helpful and interesting to students as
they might face quicksort as a question in their examinations. So, it is important to
discuss the topic.
Sorting is a way of arranging items in a systematic manner. Quicksort is the widely used
sorting algorithm that makes n log n comparisons in average case for sorting an array
of n elements. It is a faster and highly efficient sorting algorithm. This algorithm follows
the divide and conquer approach. Divide and conquer is a technique of breaking down
the algorithms into subproblems, then solving the subproblems, and combining the
results back together to solve the original problem.
Divide: In Divide, first pick a pivot element. After that, partition or rearrange the array
into two sub-arrays such that each element in the left sub-array is less than or equal to
the pivot element and each element in the right sub-array is larger than the pivot
element.
169
Quicksort picks an element as pivot, and then it partitions the given array around the
picked pivot element. In quick sort, a large array is divided into two arrays in which one
holds values that are smaller than the specified value (Pivot), and another array holds
the values that are greater than the pivot.
After that, left and right sub-arrays are also partitioned using the same approach. It will
continue until the single element remains in the sub-array.
Picking a good pivot is necessary for the fast implementation of quicksort. However, it is
typical to determine a good pivot. Some of the ways of choosing a pivot are as follows -
o Pivot can be random, i.e. select the random pivot from the given array.
o Pivot can either be the rightmost element of the leftmost element of the given
array.
o Select median as the pivot element.
Algorithm
Algorithm:
170
9. }
Partition Algorithm:
To understand the working of quick sort, let's take an unsorted array. It will make the
concept more clear and understandable.
In the given array, we consider the leftmost element as pivot. So, in this case, a[left] =
24, a[right] = 27 and a[pivot] = 24.
Since, pivot is at left, so algorithm starts from right and move towards left.
171
Now, a[pivot] < a[right], so algorithm moves forward one position towards left, i.e. -
Because, a[pivot] > a[right], so, algorithm will swap a[pivot] with a[right], and pivot
moves to right, as -
Now, a[left] = 19, a[right] = 24, and a[pivot] = 24. Since, pivot is at right, so algorithm
starts from left and moves to right.
Now, a[left] = 9, a[right] = 24, and a[pivot] = 24. As a[pivot] > a[left], so algorithm
moves one position to right as -
Now, a[left] = 29, a[right] = 24, and a[pivot] = 24. As a[pivot] < a[left], so, swap a[pivot]
and a[left], now pivot is at left, i.e. -
172
Since, pivot is at left, so algorithm starts from right, and move to left. Now, a[left] = 24,
a[right] = 29, and a[pivot] = 24. As a[pivot] < a[right], so algorithm moves one position
to left, as -
Now, a[pivot] = 24, a[left] = 24, and a[right] = 14. As a[pivot] > a[right], so, swap a[pivot]
and a[right], now pivot is at right, i.e. -
Now, a[pivot] = 24, a[left] = 14, and a[right] = 24. Pivot is at right, so the algorithm starts
from left and move to right.
Now, a[pivot] = 24, a[left] = 24, and a[right] = 24. So, pivot, left and right are pointing
the same element. It represents the termination of procedure.
Element 24, which is the pivot element is placed at its exact position.
Elements that are right side of element 24 are greater than it, and the elements that are
left side of element 24 are smaller than it.
173
Now, in a similar manner, quick sort algorithm is separately applied to the left and right
sub-arrays. After sorting gets done, the array will be -
Quicksort complexity
Now, let's see the time complexity of quicksort in best case, average case, and in worst
case. We will also see the space complexity of quicksort.
In this article, we will discuss the merge sort Algorithm. Merge sort is the sorting
technique that follows the divide and conquer approach. This article will be very helpful
and interesting to students as they might face merge sort as a question in their
examinations. In coding or technical interviews for software engineers, sorting
algorithms are widely asked. So, it is important to discuss the topic.
Merge sort is similar to the quick sort algorithm as it uses the divide and conquer
approach to sort the elements. It is one of the most popular and efficient sorting
algorithm. It divides the given list into two equal halves, calls itself for the two halves
and then merges the two sorted halves. We have to define the merge() function to
perform the merging.
The sub-lists are divided again and again into halves until the list cannot be divided
further. Then we combine the pair of one element lists into two-element lists, sorting
them in the process. The sorted two-element pairs is merged into the four-element lists,
and so on until we get the sorted list.
Algorithm
In the following algorithm, arr is the given array, beg is the starting element, and end is
the last element of the array.
174
2.
3. if beg < end
4. set mid = (beg + end)/2
5. MERGE_SORT(arr, beg, mid)
6. MERGE_SORT(arr, mid + 1, end)
7. MERGE (arr, beg, mid, end)
8. end of if
9.
10. END MERGE_SORT
The important part of the merge sort is the MERGE function. This function performs the
merging of two sorted sub-arrays that are A[beg…mid] and A[mid+1…end], to build
one sorted array A[beg…end]. So, the inputs of the MERGE function are A[], beg,
mid, and end.
175
20. while (i < n1 && j < n2)
21. {
22. if(LeftArray[i] <= RightArray[j])
23. {
24. a[k] = LeftArray[i];
25. i++;
26. }
27. else
28. {
29. a[k] = RightArray[j];
30. j++;
31. }
32. k++;
33. }
34. while (i<n1)
35. {
36. a[k] = LeftArray[i];
37. i++;
38. k++;
39. }
40.
41. while (j<n2)
42. {
43. a[k] = RightArray[j];
44. j++;
45. k++;
46. }
47. }
To understand the working of the merge sort algorithm, let's take an unsorted array. It
will be easier to understand the merge sort via an example.
176
Let the elements of array are -
According to the merge sort, first divide the given array into two equal halves. Merge
sort keeps dividing the list into equal parts until it cannot be further divided.
As there are eight elements in the given array, so it is divided into two arrays of size 4.
Now, again divide these two arrays into halves. As they are of size 4, so divide them into
new arrays of size 2.
Now, again divide these arrays to get the atomic value that cannot be further divided.
In combining, first compare the element of each array and then combine them into
another array in sorted order.
So, first compare 12 and 31, both are in sorted positions. Then compare 25 and 8, and in
the list of two values, put 8 first followed by 25. Then compare 32 and 17, sort them and
put 17 first followed by 32. After that, compare 40 and 42, and place them sequentially.
In the next iteration of combining, now compare the arrays with two data values and
merge them into an array of found values in sorted order.
177
Now, there is a final merging of the arrays. After the final merging of above arrays, the
array will look like -
What is a Stack?
A Stack is a linear data structure that follows the LIFO (Last-In-First-Out) principle.
Stack has one end, whereas the Queue has two ends (front and rear). It contains only
one pointer top pointer pointing to the topmost element of the stack. Whenever an
element is added in the stack, it is added on the top of the stack, and the element can
be deleted only from the stack. In other words, a stack can be defined as a container
in which insertion and deletion can be done from the one end known as the top of
the stack.
Working of Stack
Stack works on the LIFO pattern. As we can observe in the below figure there are five
memory blocks in the stack; therefore, the size of the stack is 5.
Suppose we want to store the elements in a stack and let's assume that stack is empty.
We have taken the stack of size 5 as shown below in which we are pushing the elements
one by one until the stack becomes full.
178
Since our stack is full as the size of the stack is 5. In the above cases, we can observe
that it goes from the top to the bottom when we were entering the new element in the
stack. The stack gets filled up from the bottom to the top.
43.4MWhen we perform the delete operation on the stack, there is only one way for entry and
exit as the other end is closed. It follows the LIFO pattern, which means that the value entered
first will be removed last. In the above case, the value 5 is entered first, so it will be removed
only after the deletion of all the other elements.
PUSH operation
179
o Before inserting an element in a stack, we check whether the stack is full.
o If we try to insert the element in a stack, and the stack is full, then
the overflow condition occurs.
o When we initialize a stack, we set the value of top as -1 to check that the stack is
empty.
o When the new element is pushed in a stack, first, the value of the top gets
incremented, i.e., top=top+1, and the element will be placed at the new position
of the top.
o The elements will be inserted until we reach the max size of the stack.
POP operation
o Before deleting the element from the stack, we check whether the stack is empty.
o If we try to delete the element from the empty stack, then
the underflow condition occurs.
o If the stack is not empty, we first access the element which is pointed by the top
o Once the pop operation is performed, the top is decremented by 1, i.e., top=top-
1.
180
Before understanding the conversion from infix to postfix notation, we should know
about the infix and postfix notations separately.
An infix and postfix are the expressions. An expression consists of constants, variables,
and symbols. Symbols can be operators or parenthesis. All these components must be
arranged according to a set of rules so that all these expressions can be evaluated using
the set of rules.
5+6
A-B
(P * 5)
All the above expressions have a common structure, i.e., we have an operator between
the two operands. An Operand is an object or a value on which the operation is to be
performed. In the above expressions, 5, 6 are the operands while '+', '-', and '*' are the
operators.
When the operator is written in between the operands, then it is known as infix
notation. Operand does not have to be always a constant or a variable; it can also be an
expression itself.
For example,
(p + q) * (r + s)
In the above expression, both the expressions of the multiplication operator are the
operands, i.e., (p + q), and (r + s) are the operands.
In the above expression, there are three operators. The operands for the first plus
operator are p and q, the operands for the second plus operator are r and s. While
performing the operations on the expression, we need to follow some set of rules
to evaluate the result. In the above expression, addition operation would be
performed on the two expressions, i.e., p+q and r+s, and then the multiplication
operation would be performed.
181
<operand> <operator> <operand>
If there is only one operator in the expression, we do not require applying any rule. For
example, 5 + 2; in this expression, addition operation can be performed between the
two operands (5 and 2), and the result of the operation would be 7.
If there are multiple operators in the expression, then some rule needs to be followed to
evaluate the expression.
4+6*2
If the plus operator is evaluated first, then the expression would look like:
10 * 2 = 20
If the multiplication operator is evaluated first, then the expression would look like:
4 + 12 = 16
The above problem can be resolved by following the operator precedence rules. In the
algebraic expression, the order of the operator precedence is given in the below table:
Operators Symbols
Parenthesis ( ), {}, [ ]
Exponents ^
The first preference is given to the parenthesis; then next preference is given to the
exponents. In the case of multiple exponent operators, then the operation will be
applied from right to left.
182
For example:
2^2^3 = 2 ^ 8
= 256
After exponent, multiplication, and division operators are evaluated. If both the
operators are present in the expression, then the operation will be applied from left to
right.
The next preference is given to addition and subtraction. If both the operators are
available in the expression, then we go from left to right.
The operators that have the same precedence termed as operator associativity. If we
go from left to right, then it is known as left-associative. If we go from right to left, then
it is known as right-associative.
To evaluate the infix expression, we should know about the operator precedence rules,
and if the operators have the same precedence, then we should follow
the associativity rules. The use of parenthesis is very important in infix notation to
control the order in which the operation to be performed. Parenthesis improves the
readability of the expression. An infix expression is the most common way of writing
expression, but it is not easy to parse and evaluate the infix expression without
ambiguity. So, mathematicians and logicians studied this problem and discovered two
other ways of writing expressions which are prefix and postfix. Both expressions do not
require any parenthesis and can be parsed without ambiguity. It does not require
operator precedence and associativity rules.
Postfix Expression
The postfix expression is an expression in which the operator is written after the
operands. For example, the postfix expression of infix notation ( 2+3) can be written as
23+.
o In postfix expression, operations are performed in the order in which they have
written from left to right.
o It does not any require any parenthesis.
183
o We do not need to apply operator precedence rules and associativity rules.
o Scan the expression from left to right until we encounter any operator.
o Perform the operation
o Replace the expression with its computed value.
o Repeat the steps from 1 to 3 until no more operators exist.
Infix expression: 2 + 3 * 4
We will start scanning from the left most of the expression. The multiplication operator
is an operator that appears first while scanning from left to right. Now, the expression
would be:
Expression = 2 + 34*
= 2 + 12
Again, we will scan from left to right, and the expression would be:
Expression = 2 12 +
= 14
184
Example 1: Postfix expression: 2 3 4 * +
Input Stack
2 3 4 * empty Push 2
+
34*+ 2 Push 3
4*+ 32 Push 4
*+ 432 Pop 4 and 3, and perform 4*3 = 12. Push 12 into the stack.
+ 12 2 Pop 12 and 2 from the stack, and perform 12+2 = 14. Push 14
into the stack.
Input Stack
3 4 * 2 5 * empty Push 3
+
4*25*+ 3 Push 4
*2 5 * + 43 Pop 3 and 4 from the stack and perform 3*4 = 12. Push 12 into
the stack.
25*+ 12 Push 2
185
5*+ 2 12 Push 5
*+ 5 2 12 Pop 5 and 2 from the stack and perform 5*2 = 10. Push 10 into
the stack.
+ 10 12 Pop 10 and 12 from the stack and perform 10+12 = 22. Push 22
into the stack.
1. Read a character
2. If the character is a digit, convert the character into int and push the integer into
the stack.
3. If the character is an operator,
o Pop the elements from the stack twice obtaining two operands.
o Perform the operation
o Push the result into the stack.
Here, we will use the stack data structure for the conversion of infix expression to prefix
expression. Whenever an operator will encounter, we push operator into the stack. If we
encounter an operand, then we append the operand to the expression.
186
4. If the incoming symbol is ')', pop the stack and print the operators until the left
parenthesis is found.
5. If the incoming symbol has higher precedence than the top of the stack, push it
on the stack.
6. If the incoming symbol has lower precedence than the top of the stack, pop and
print the top of the stack. Then test the incoming operator against the new top of
the stack.
7. If the incoming operator has the same precedence with the top of the stack then
use the associativity rules. If the associativity is from left to right then pop and
print the top of the stack then push the incoming operator. If the associativity is
from right to left then push the incoming operator.
8. At the end of the expression, pop and print all the operators of the stack.
K K
+ +
L + KL
- - K L+
M - K L+ M
* -* K L+ M
N -* KL+MN
187
+ + K L + M N*
K L + M N* -
( +( K L + M N *-
O +( KL+MN*-O
^ +(^ K L + M N* - O
P +(^ K L + M N* - O P
) + K L + M N* - O P ^
* +* K L + M N* - O P ^
W +* K L + M N* - O P ^ W
/ +/ K L + M N* - O P ^ W *
U +/ K L + M N* - O P ^W*U
/ +/ K L + M N* - O P ^W*U/
V +/ KL + MN*-OP^W*U/V
* +* KL+MN*-OP^W*U/V/
T +* KL+MN*-OP^W*U/V/T
+ + KL+MN*-OP^W*U/V/T*
188
KL+MN*-OP^W*U/V/T*+
Q + KL+MN*-OP^W*U/V/T*Q
KL+MN*-OP^W*U/V/T*+Q+
Before understanding the conversion from infix to postfix notation, we should know
about the infix and postfix notations separately.
An infix and postfix are the expressions. An expression consists of constants, variables,
and symbols. Symbols can be operators or parenthesis. All these components must be
arranged according to a set of rules so that all these expressions can be evaluated using
the set of rules.
5+6
A-B
189
(P * 5)
All the above expressions have a common structure, i.e., we have an operator between
the two operands. An Operand is an object or a value on which the operation is to be
performed. In the above expressions, 5, 6 are the operands while '+', '-', and '*' are the
operators.
When the operator is written in between the operands, then it is known as infix
notation. Operand does not have to be always a constant or a variable; it can also be an
expression itself.
For example,
(p + q) * (r + s)
In the above expression, both the expressions of the multiplication operator are the
operands, i.e., (p + q), and (r + s) are the operands.
In the above expression, there are three operators. The operands for the first plus
operator are p and q, the operands for the second plus operator are r and s. While
performing the operations on the expression, we need to follow some set of rules
to evaluate the result. In the above expression, addition operation would be
performed on the two expressions, i.e., p+q and r+s, and then the multiplication
operation would be performed.
If there is only one operator in the expression, we do not require applying any rule. For
example, 5 + 2; in this expression, addition operation can be performed between the
two operands (5 and 2), and the result of the operation would be 7.
If there are multiple operators in the expression, then some rule needs to be followed to
evaluate the expression.
4+6*2
190
If the plus operator is evaluated first, then the expression would look like:
10 * 2 = 20
If the multiplication operator is evaluated first, then the expression would look like:
4 + 12 = 16
The above problem can be resolved by following the operator precedence rules. In the
algebraic expression, the order of the operator precedence is given in the below table:
Operators Symbols
Parenthesis ( ), {}, [ ]
Exponents ^
The first preference is given to the parenthesis; then next preference is given to the
exponents. In the case of multiple exponent operators, then the operation will be
applied from right to left.
For example:
2^2^3 = 2 ^ 8
= 256
After exponent, multiplication, and division operators are evaluated. If both the
operators are present in the expression, then the operation will be applied from left to
right.
The next preference is given to addition and subtraction. If both the operators are
available in the expression, then we go from left to right.
191
The operators that have the same precedence termed as operator associativity. If we
go from left to right, then it is known as left-associative. If we go from right to left, then
it is known as right-associative.
To evaluate the infix expression, we should know about the operator precedence rules,
and if the operators have the same precedence, then we should follow
the associativity rules. The use of parenthesis is very important in infix notation to
control the order in which the operation to be performed. Parenthesis improves the
readability of the expression. An infix expression is the most common way of writing
expression, but it is not easy to parse and evaluate the infix expression without
ambiguity. So, mathematicians and logicians studied this problem and discovered two
other ways of writing expressions which are prefix and postfix. Both expressions do not
require any parenthesis and can be parsed without ambiguity. It does not require
operator precedence and associativity rules.
Postfix Expression
The postfix expression is an expression in which the operator is written after the
operands. For example, the postfix expression of infix notation ( 2+3) can be written as
23+.
o In postfix expression, operations are performed in the order in which they have
written from left to right.
o It does not any require any parenthesis.
o We do not need to apply operator precedence rules and associativity rules.
o Scan the expression from left to right until we encounter any operator.
o Perform the operation
o Replace the expression with its computed value.
o Repeat the steps from 1 to 3 until no more operators exist.
192
Infix expression: 2 + 3 * 4
We will start scanning from the left most of the expression. The multiplication operator
is an operator that appears first while scanning from left to right. Now, the expression
would be:
Expression = 2 + 34*
= 2 + 12
Again, we will scan from left to right, and the expression would be:
Expression = 2 12 +
= 14
Input Stack
2 3 4 * empty Push 2
+
34*+ 2 Push 3
193
4*+ 32 Push 4
*+ 432 Pop 4 and 3, and perform 4*3 = 12. Push 12 into the stack.
+ 12 2 Pop 12 and 2 from the stack, and perform 12+2 = 14. Push 14
into the stack.
Input Stack
3 4 * 2 5 * empty Push 3
+
4*25*+ 3 Push 4
*2 5 * + 43 Pop 3 and 4 from the stack and perform 3*4 = 12. Push 12 into the
stack.
25*+ 12 Push 2
5*+ 2 12 Push 5
*+ 5 2 12 Pop 5 and 2 from the stack and perform 5*2 = 10. Push 10 into the
stack.
+ 10 12 Pop 10 and 12 from the stack and perform 10+12 = 22. Push 22
into the stack.
194
The result of the above expression is 22.
1. Read a character
2. If the character is a digit, convert the character into int and push the integer into
the stack.
3. If the character is an operator,
o Pop the elements from the stack twice obtaining two operands.
o Perform the operation
o Push the result into the stack.
Here, we will use the stack data structure for the conversion of infix expression to prefix
expression. Whenever an operator will encounter, we push operator into the stack. If we
encounter an operand, then we append the operand to the expression.
K K
195
+ +
L + KL
- - K L+
M - K L+ M
* -* K L+ M
N -* KL+MN
+ + K L + M N*
K L + M N* -
( +( K L + M N *-
O +( KL+MN*-O
^ +(^ K L + M N* - O
P +(^ K L + M N* - O P
) + K L + M N* - O P ^
* +* K L + M N* - O P ^
W +* K L + M N* - O P ^ W
/ +/ K L + M N* - O P ^ W *
196
U +/ K L + M N* - O P ^W*U
/ +/ K L + M N* - O P ^W*U/
V +/ KL + MN*-OP^W*U/V
* +* KL+MN*-OP^W*U/V/
T +* KL+MN*-OP^W*U/V/T
+ + KL+MN*-OP^W*U/V/T*
KL+MN*-OP^W*U/V/T*+
Q + KL+MN*-OP^W*U/V/T*Q
KL+MN*-OP^W*U/V/T*+Q+
4. If the incoming symbol is ')', pop the stack and print the operators until the left
parenthesis is found.
5. If the incoming symbol has higher precedence than the top of the stack, push it
on the stack.
197
6. If the incoming symbol has lower precedence than the top of the stack, pop and
print the top of the stack. Then test the incoming operator against the new top of
the stack.
7. If the incoming operator has the same precedence with the top of the stack then
use the associativity rules. If the associativity is from left to right then pop and
print the top of the stack then push the incoming operator. If the associativity is
from right to left then push the incoming operator.
8. At the end of the expression, pop and print all the operators of the stack.
placed after the operands. That means, in a postfix expression the operator follows the
operands.
Example
198
A postfix expression can be evaluated using the Stack data structure. To evaluate a
postfix expression using Stack data structure we can use the following steps...
1. Read all the symbols one by one from left to right in the given Postfix
Expression
operations and store the two popped oparands in two different variables
4. Finally! perform a pop operation and display the popped value as final
result.
Example
199
200
Stack Using Array
A stack data structure can be implemented using a one-dimensional array. But stack
implemented using array stores only a fixed number of data values. This implementation
is very simple. Just define a one dimensional array of specific size and insert or delete
the values into that array by using LIFO principle with the help of a variable called 'top'.
Initially, the top is set to -1. Whenever we want to insert a value into the stack,
increment the top value by one and then insert. Whenever we want to delete a value
from the stack, then delete the top value and decrement the top value by one.
Before implementing actual operations, first follow the below steps to create an empty
stack.
Step 1 - Include all the header files which are used in the program and define a
Step 3 - Create a one dimensional array with fixed size (int stack[SIZE])
Step 4 - Define a integer variable 'top' and initialize with '-1'. (int top = -1)
Step 5 - In main method, display menu with list of operations and make suitable
In a stack, push() is a function used to insert an element into the stack. In a stack, the
new element is always inserted at top position. Push function takes one integer value as
parameter and inserts that value into the stack. We can use the following steps to push
201
Step 1 - Check whether stack is FULL. (top == SIZE-1)
Step 3 - If it is NOT FULL, then increment top value by one (top++) and set
In a stack, pop() is a function used to delete an element from the stack. In a stack, the
element is always deleted from top position. Pop function does not take any value as
parameter. We can use the following steps to pop an element from the stack...
Step 3 - If it is NOT EMPTY, then delete stack[top] and decrement top value by
one (top--).
function.
Step 3 - If it is NOT EMPTY, then define a variable 'i' and initialize with top.
202
#include<conio.h>
#define SIZE 10
void push(int);
void pop();
void display();
int stack[SIZE], top = -1;
void main()
{
int value, choice;
clrscr();
while(1){
printf("\n\n***** MENU *****\n");
printf("1. Push\n2. Pop\n3. Display\n4. Exit");
printf("\nEnter your choice: ");
scanf("%d",&choice);
switch(choice){
case 1: printf("Enter the value to be insert: ");
scanf("%d",&value);
push(value);
break;
case 2: pop();
break;
case 3: display();
break;
case 4: exit(0);
default: printf("\nWrong selection!!! Try again!!!");
}
203
}
}
void push(int value){
if(top == SIZE-1)
printf("\nStack is Full!!! Insertion is not possible!!!");
else{
top++;
stack[top] = value;
printf("\nInsertion success!!!");
}
}
void pop(){
if(top == -1)
printf("\nStack is Empty!!! Deletion is not possible!!!");
else{
printf("\nDeleted : %d", stack[top]);
top--;
}
}
void display(){
if(top == -1)
printf("\nStack is Empty!!!");
else{
int i;
printf("\nStack elements are:\n");
for(i=top; i>=0; i--)
printf("%d\n",stack[i]);
204
}
}
Output
Queue?
Queue is the data structure that is similar to the queue in the real world. A queue is a
data structure in which whatever comes first will go out first, and it follows the FIFO
(First-In-First-Out) policy. Queue can also be defined as the list or collection in which the
insertion is done from one end known as the rear end or the tail of the queue, whereas
the deletion is done from another end known as the front end or the head of the
queue.
The real-world example of a queue is the ticket queue outside a cinema hall, where the
person who enters first in the queue gets the ticket first, and the last person enters in
the queue gets the ticket at last. Similar approach is followed in the queue in data
structure.
205
Now, let's move towards the types of queue.
Types of Queue
There are four different types of queue that are listed as follows -
In Linear Queue, an insertion takes place from one end while the deletion occurs from
another end. The end at which the insertion takes place is known as the rear end, and
the end at which the deletion takes place is known as front end. It strictly follows the
FIFO rule.
206
The major drawback of using a linear Queue is that insertion is done only from the rear
end. If the first three elements are deleted from the Queue, we cannot insert more
elements even though the space is available in a Linear Queue. In this case, the linear
Queue shows the overflow condition as the rear is pointing to the last element of the
Queue.
To know more about the queue in data structure, you can click the link -
https://www.javatpoint.com/data-structure-queue
Circular Queue
In Circular Queue, all the nodes are represented as circular. It is similar to the linear
Queue except that the last element of the queue is connected to the first element. It is
also known as Ring Buffer, as all the ends are connected to another end. The
representation of circular queue is shown in the below image -
The drawback that occurs in a linear queue is overcome by using the circular queue. If
the empty space is available in a circular queue, the new element can be added in an
empty space by simply incrementing the value of rear. The main advantage of using the
circular queue is better memory utilization.
To know more about the circular queue, you can click the link -
https://www.javatpoint.com/circular-queue
Priority Queue
It is a special type of queue in which the elements are arranged based on the priority. It
is a special type of queue data structure in which every element has a priority associated
with it. Suppose some elements occur with the same priority, they will be arranged
according to the FIFO principle. The representation of priority queue is shown in the
below image -
207
Insertion in priority queue takes place based on the arrival, while deletion in the priority
queue occurs based on the priority. Priority queue is mainly used to implement the CPU
scheduling algorithms.
There are two types of priority queue that are discussed as follows -
In Deque or Double Ended Queue, insertion and deletion can be done from both ends
of the queue either from the front or rear. It means that we can insert and delete
elements from both front and rear ends of the queue. Deque can be used as a
palindrome checker means that if we read the string from both ends, then the string
would be the same.
Deque can be used both as stack and queue as it allows the insertion and deletion
operations on both ends. Deque can be considered as stack because stack follows the
LIFO (Last In First Out) principle in which insertion and deletion both can be performed
only from one end. And in deque, it is possible to perform both insertion and deletion
from one end, and Deque does not follow the FIFO principle.
208
To know more about the deque, you can click the link - https://www.javatpoint.com/ds-
deque
o Input restricted deque - As the name implies, in input restricted queue, insertion
operation can be performed at only one end, while deletion can be performed
from both ends.
Application of Queue
209
A queue data structure is generally used in scenarios where the FIFO approach (First In
First Out) has to be implemented. The following are some of the most common
applications of queue in data structure:
Managing requests on a single shared resource such as CPU scheduling and disk
scheduling
Handling hardware or real-time systems interrupts
Handling website traffic
Routers and switches in networking
Maintaining the playlist in media players
A queue data structure can be implemented using one dimensional array. The queue
implemented using array stores only fixed number of data values. The implementation
of queue data structure using array is very simple. Just define a one dimensional array of
specific size and insert or delete the values into that array by using FIFO (First In First
Out) principle with the help of variables 'front' and 'rear'. Initially both 'front' and
'rear' are set to -1. Whenever, we want to insert a new value into the queue, increment
'rear' value by one and then insert at that position. Whenever we want to delete a value
from the queue, then delete the element which is at 'front' position and increment
Before we implement actual operations, first follow the below steps to create an empty
queue.
Step 1 - Include all the header files which are used in the program and define a
210
Step 2 - Declare all the user defined functions which are used in queue
implementation.
Step 3 - Create a one dimensional array with above defined SIZE (int
queue[SIZE])
Step 4 - Define two integer variables 'front' and 'rear' and initialize both with '-
Step 5 - Then implement main method by displaying menu of operations list and
make suitable function calls to perform operation selected by the user on queue.
In a queue data structure, enQueue() is a function used to insert a new element into the
queue. In a queue, the new element is always inserted at rear position. The enQueue()
function takes one integer value as a parameter and inserts that value into the queue.
We can use the following steps to insert an element into the queue...
Step 3 - If it is NOT FULL, then increment rear value by one (rear++) and
In a queue data structure, deQueue() is a function used to delete an element from the
queue. In a queue, the element is always deleted from front position. The deQueue()
function does not take any value as parameter. We can use the following steps to delete
211
Step 2 - If it is EMPTY, then display "Queue is EMPTY!!! Deletion is not
Step 3 - If it is NOT EMPTY, then increment the front value by one (front ++).
both front and rear are equal (front == rear), if it TRUE, then set
function.
Step 3 - If it is NOT EMPTY, then define an integer variable 'i' and set
'i = front+1'.
Step 4 - Display 'queue[i]' value and increment 'i' value by one (i++). Repeat the
212
int value, choice;
clrscr();
while(1){
printf("\n\n***** MENU *****\n");
printf("1. Insertion\n2. Deletion\n3. Display\n4. Exit");
printf("\nEnter your choice: ");
scanf("%d",&choice);
switch(choice){
case 1: printf("Enter the value to be insert: ");
scanf("%d",&value);
enQueue(value);
break;
case 2: deQueue();
break;
case 3: display();
break;
case 4: exit(0);
default: printf("\nWrong selection!!! Try again!!!");
}
}
}
void enQueue(int value){
if(rear == SIZE-1)
printf("\nQueue is Full!!! Insertion is not possible!!!");
else{
if(front == -1)
front = 0;
213
rear++;
queue[rear] = value;
printf("\nInsertion success!!!");
}
}
void deQueue(){
if(front == rear)
printf("\nQueue is Empty!!! Deletion is not possible!!!");
else{
printf("\nDeleted : %d", queue[front]);
front++;
if(front == rear)
front = rear = -1;
}
}
void display(){
if(rear == -1)
printf("\nQueue is Empty!!!");
else{
int i;
printf("\nQueue elements are:\n");
for(i=front; i<=rear; i++)
printf("%d\t",queue[i]);
}
}
Output
214
215
UNIT-5
Linked List
o Linked List can be defined as collection of objects called nodes that are randomly
stored in the memory.
o A node contains two fields i.e. data stored at that particular address and the
pointer which contains the address of the next node in the memory.
o The last node of the list contains pointer to the null.
o The list is not required to be contiguously present in the memory. The node can
reside any where in the memory and linked together to make a list. This achieves
optimized utilization of space.
o list size is limited to the memory size and doesn't need to be declared in advance.
o Empty node can not be present in the linked list.
o We can store values of primitive types or objects in the singly linked list.
o Singly linked list can be defined as the collection of ordered set of elements. The
number of elements may vary according to need of the program. A node in the
singly linked list consist of two parts: data part and link part. Data part of the
node stores actual information that is to be represented by the node while the
link part of the node stores the address of its immediate successor.
o 45.1M
o 841
o Difference between JDK, JRE, and JVM
216
o One way chain or singly linked list can be traversed only in one direction. In other
words, we can say that each node contains only next pointer, therefore we can
not traverse the list in the reverse direction.
o Consider an example where the marks obtained by the student in three subjects
are stored in a linked list as shown in the figure.
o
o In the above figure, the arrow represents the links. The data part of every node
contains the marks obtained by the student in the different subject. The last node
in the list is identified by the null pointer which is present in the address part of
the last node. We can have as many elements we require, in the data part of the
list.
There are various operations which can be performed on singly linked list. A list of all
such operations is given below.
Node Creation
1. struct node
2. {
3. int data;
4. struct node *next;
5. };
6. struct node *head, *ptr;
7. ptr = (struct node *)malloc(sizeof(struct node *));
Insertion
The insertion into a singly linked list can be performed at different positions. Based on
the position of the new node being inserted, the insertion is categorized into the
following categories.
The Deletion of a node from a singly linked list can be performed at different positions.
Based on the position of the node being deleted, the operation is categorized into the
following categories.
217
Linked List in C: Menu Driven Program
1. #include<stdio.h>
218
219
Doubly linked list
Doubly linked list is a complex type of linked list in which a node contains a pointer to
the previous as well as the next node in the sequence. Therefore, in a doubly linked list,
a node consists of three parts: node data, pointer to the next node in sequence (next
pointer) , pointer to the previous node (previous pointer). A sample node in a doubly
linked list is shown in the figure.
A doubly linked list containing three nodes having numbers from 1 to 3 in their data
part, is shown in the following image.
1. struct node
2. {
3. struct node *prev;
4. int data;
5. struct node *next;
6. }
The prev part of the first node and the next part of the last node will always contain null
indicating end in each direction.
220
In a singly linked list, we could traverse only in one direction, because each node
contains address of the next node and it doesn't have any record of its previous nodes.
However, doubly linked list overcome this limitation of singly linked list. Due to the fact
that, each node of the list contains the address of its previous node, we can find all the
details about the previous node as well by using the previous address stored inside the
previous part of each node.
In the following image, the first element of the list that is i.e. 13 stored at address 1. The
head pointer points to the starting address 1. Since this is the first element being added
to the list therefore the prev of the list contains null. The next node of the list resides at
address 4 therefore the first node contains 4 in its next pointer.
We can traverse the list in this way until we find any node containing null or -1 in its
next part.
221
Operations on doubly linked list
Node Creation
1. struct node
2. {
3. struct node *prev;
4. int data;
5. struct node *next;
6. };
7. struct node *head;
All the remaining operations regarding doubly linked list are described in the following
table.
222
Circular Linked List
Circular Linked List is a variation of Linked list in which the first element points to the
last element and the last element points to the first element. Both Singly Linked List
and Doubly Linked List can be made into a circular linked list.
In singly linked list, the next pointer of the last node points to the first node.
In doubly linked list, the next pointer of the last node points to the first node and the
previous pointer of the first node points to the last node making the circular in both
directions.
As per the above illustration, following are the important points to be considered.
The last link's next points to the first link of the list in both cases of singly as well
as doubly linked list.
The first link's previous points to the last of the list in case of doubly linked list.
Basic Operations
Insertion Operation
223
Following code demonstrates the insertion operation in a circular linked list based on
single linked list.
Example
insertFirst(data):
Begin
create a new node
node -> data := data
if the list is empty, then
head := node
next of node = head
else
temp := head
while next of temp is not head, do
temp := next of temp
done
next of node := head
next of temp := node
head := node
end if
End
Deletion Operation
Following code demonstrates the deletion operation in a circular linked list based on
single linked list.
deleteFirst():
Begin
if head is null, then
it is Underflow and return
else if next of head = head, then
head := null
deallocate head
else
ptr := head
while next of ptr is not head, do
ptr := next of ptr
next of ptr = next of head
deallocate head
head := next of ptr
224
end if
End
Following code demonstrates the display list operation in a circular linked list.
display():
Begin
if head is null, then
Nothing to print and return
else
ptr := head
while next of ptr is not head, do
display data of ptr
ptr := next of ptr
display data of ptr
end if
End
Trees
We read the linear data structures like an array, linked list, stack and queue in which all
the elements are arranged in a sequential manner. The different data structures are used
for different kinds of data.
225
A tree is also one of the data structures that represent hierarchical data. Suppose we
want to show the employees and their positions in the hierarchical form then it can be
represented as shown below:
The above tree shows the organization hierarchy of some company. In the above
structure, john is the CEO of the company, and John has two direct reports named
as Steve and Rohan. Steve has three direct reports named Lee, Bob, Ella where Steve is
a manager. Bob has two direct reports named Sal and Emma. Emma has two direct
reports named Tom and Raj. Tom has one direct report named Bill. This particular
logical structure is known as a Tree. Its structure is similar to the real tree, so it is named
a Tree. In this structure, the root is at the top, and its branches are moving in a
downward direction. Therefore, we can say that the Tree data structure is an efficient
way of storing the data in a hierarchical way.
226
Let's consider the tree structure, which is shown below:
In the above structure, each node is labeled with some number. Each arrow shown in the
above figure is known as a link between the two nodes.
o Root: The root node is the topmost node in the tree hierarchy. In other words,
the root node is the one that doesn't have any parent. In the above structure,
node numbered 1 is the root node of the tree. If a node is directly linked to
some other node, it would be called a parent-child relationship.
o Child node: If the node is a descendant of any node, then the node is known as a
child node.
o Parent: If the node contains any sub-node, then that node is said to be the
parent of that sub-node.
o Sibling: The nodes that have the same parent are known as siblings.
o Leaf Node:- The node of the tree, which doesn't have any child node, is called a
leaf node. A leaf node is the bottom-most node of the tree. There can be any
number of leaf nodes present in a general tree. Leaf nodes can also be called
external nodes.
o Internal nodes: A node has atleast one child node known as an internal
o Ancestor node:- An ancestor of a node is any predecessor node on a path from
the root to that node. The root node doesn't have any ancestors. In the tree
shown in the above image, nodes 1, 2, and 5 are the ancestors of node 10.
227
o Descendant: The immediate successor of the given node is known as a
descendant of a node. In the above figure, 10 is the descendant of node 5.
Binary Tree
The Binary tree means that the node can have maximum two children. Here, binary
name itself suggests that 'two'; therefore, each node can have either 0, 1 or 2 children.
The above tree is a binary tree because each node contains the utmost two children. The
logical representation of the above tree is given below:
In the above tree, node 1 contains two pointers, i.e., left and a right pointer pointing to
the left and right node respectively. The node 2 contains both the nodes (left and right
node); therefore, it has two pointers (left and right). The nodes 3, 5 and 6 are the leaf
nodes, so all these nodes contain NULL pointer on both left and right parts
228
the maximum number of nodes possible at height h is (20 + 21 + 22+….2h) =
2h+1 -1.
o The minimum number of nodes possible at height h is equal to h+1.
o If the number of nodes is minimum, then the height of the tree would be
maximum. Conversely, if the number of nodes is maximum, then the height of the
tree would be minimum.
As we know that,
n = 2h+1 -1
n+1 = 2h+1
log2(n+1) = log2(2h+1)
log2(n+1) = h+1
h = log2(n+1) - 1
As we know that,
n = h+1
h= n-1
229
o Degenerate Binary tree
o Balanced Binary tree
The full binary tree is also known as a strict binary tree. The tree can only be considered
as the full binary tree if each node must contain either 0 or 2 children. The full binary
tree can also be defined as the tree in which each node must contain 2 children except
the leaf nodes.
In the above tree, we can observe that each node is either containing zero or two
children; therefore, it is a Full Binary tree.
o The number of leaf nodes is equal to the number of internal nodes plus 1. In the
above example, the number of internal nodes is 5; therefore, the number of leaf
nodes is equal to 6.
o The maximum number of nodes is the same as the number of nodes in the binary
tree, i.e., 2h+1 -1.
o The minimum number of nodes in the full binary tree is 2*h-1.
o The minimum height of the full binary tree is log2(n+1) - 1.
o The maximum height of the full binary tree can be computed as:
n= 2*h - 1
n+1 = 2*h
230
h = n+1/2
The complete binary tree is a tree in which all the nodes are completely filled except the
last level. In the last level, all the nodes must be as left as possible. In a complete binary
tree, the nodes should be added from the left.
The above tree is a complete binary tree because all the nodes are completely filled, and
all the nodes in the last level are added at the left first.
A tree is a perfect binary tree if all the internal nodes have 2 children, and all the leaf
nodes are at the same level.
231
Let's look at a simple example of a perfect binary tree.
The below tree is not a perfect binary tree because all the leaf nodes are not at the same
level.
The degenerate binary tree is a tree in which all the internal nodes have only one
children.
232
The above tree is a degenerate binary tree because all the nodes have only one child. It
is also known as a right-skewed tree as all the nodes have a right child only.
The above tree is also a degenerate binary tree because all the nodes have only one
child. It is also known as a left-skewed tree as all the nodes have a left child only.
The balanced binary tree is a tree in which both the left and right trees differ by atmost
1. For example, AVL and Red-Black trees are balanced binary tree.
The above tree is a balanced binary tree because the difference between the left subtree
and right subtree is zero.
233
The above tree is not a balanced binary tree because the difference between the left
subtree and the right subtree is greater than 1.
A Binary tree is implemented with the help of pointers. The first node in the tree is
represented by the root pointer. Each node in the tree consists of three parts, i.e., data,
left pointer and right pointer. To create a binary tree, we first need to create the node.
We will create the node of user-defined as shown below:
1. struct node
2. {
3. int data,
4. struct node *left, *right;
5. }
In the above structure, data is the value, left pointer contains the address of the left
node, and right pointer contains the address of the right node.
Terminology
In linear data structure data is organized in sequential order and in non-linear data
structure data is organized in random order. A tree is a very popular non-linear data
structure used in a wide range of applications. A tree data structure can be defined as
follows...
structure recursively
In tree data structure, every individual element is called as Node. Node in a tree data
structure stores the actual data of that particular element and link to next element in
234
hierarchical structure.
In a tree data structure, if we have N number of nodes then we can have a maximum
Example
Terminology
1. Root
In a tree data structure, the first node is called as Root Node. Every tree must have a
root node. We can say that the root node is the origin of the tree data structure. In any
tree, there must be only one root node. We never have multiple root nodes in a tree.
2. Edge
In a tree data structure, the connecting link between any two nodes is called as EDGE. In
a tree with 'N' number of nodes there will be a maximum of 'N-1' number of edges.
235
3. Parent
In a tree data structure, the node which is a predecessor of any node is called
as PARENT NODE. In simple words, the node which has a branch from it to any other
node is called a parent node. Parent node can also be defined as "The node which has
child / children".
4. Child
In a tree data structure, the node which is descendant of any node is called as CHILD
Node. In simple words, the node which has a link from its parent node is called as child
node. In a tree, any parent node can have any number of child nodes. In a tree, all the
236
5. Siblings
In a tree data structure, nodes which belong to same Parent are called as SIBLINGS. In
simple words, the nodes with the same parent are called Sibling nodes.
6. Leaf
In a tree data structure, the node which does not have a child is called as LEAF Node. In
In a tree data structure, the leaf nodes are also called as External Nodes. External node
is also a node with no child. In a tree, leaf node is also called as 'Terminal' node.
7. Internal Nodes
In a tree data structure, the node which has atleast one child is called as INTERNAL
Node. In simple words, an internal node is a node with atleast one child.
In a tree data structure, nodes other than leaf nodes are called as Internal Nodes. The
root node is also said to be Internal Node if the tree has more than one node. Internal
237
8. Degree
In a tree data structure, the total number of children of a node is called as DEGREE of
that Node. In simple words, the Degree of a node is total number of children it has. The
highest degree of a node among all the nodes in a tree is called as 'Degree of Tree'
9. Level
In a tree data structure, the root node is said to be at Level 0 and the children of root
node are at Level 1 and the children of the nodes which are at Level 1 will be at Level 2
and so on... In simple words, in a tree each step from top to bottom is called as a Level
and the Level count starts with '0' and incremented by one at each level (Step).
238
10. Height
In a tree data structure, the total number of edges from leaf node to a particular node in
the longest path is called as HEIGHT of that Node. In a tree, height of the root node is
said to be height of the tree. In a tree, height of all leaf nodes is '0'.
11. Depth
In a tree data structure, the total number of egdes from root node to a particular node is
called as DEPTH of that Node. In a tree, the total number of edges from root node to a
leaf node in the longest path is said to be Depth of the tree. In simple words, the
highest depth of any leaf node in a tree is said to be depth of that tree. In a tree, depth
12. Path
In a tree data structure, the sequence of Nodes and Edges from one node to another
node is called as PATH between that two Nodes. Length of a Path is total number of
239
13. Sub Tree
In a tree data structure, each child from a node forms a subtree recursively. Every child
Tree Representations
A tree data structure can be represented in two methods. Those methods are as
follows...
1. List Representation
240
1. List Representation
In this representation, we use two types of nodes one for representing the node with
data called 'data node' and another for representing only references called 'reference
node'. We start with a 'data node' from the root node in the tree. Then it is linked to an
internal node through a 'reference node' which is further linked to any other node
directly. This process repeats for all the nodes in the tree.
The above example tree can be represented using List representation as follows...
In this representation, we use a list with one type of node which consists of three fields
namely Data field, Left child reference field and Right sibling reference field. Data field
stores the actual value of a node, left reference field stores the address of the left child
and right reference field stores the address of the right sibling node. Graphical
241
In this representation, every node's data field stores the actual value of that node. If that
node has left a child, then left reference field stores the address of that left child node
otherwise stores NULL. If that node has the right sibling, then right reference field stores
The above example tree can be represented using Left Child - Right Sibling
representation as follows...
In this article, we will discuss the tree traversal in the data structure. The term 'tree
traversal' means traversing or visiting each node of a tree. There is a single way to
traverse the linear data structure such as linked list, queue, and stack. Whereas, there are
multiple ways to traverse a tree that are listed as follows -
o Preorder traversal
o Inorder traversal
o Postorder traversal
So, in this article, we will discuss the above-listed techniques of traversing a tree. Now,
let's start discussing the ways of tree traversal.
242
Preorder traversal
This technique follows the 'root left right' policy. It means that, first root node is visited
after that the left subtree is traversed recursively, and finally, right subtree is recursively
traversed. As the root node is traversed before (or pre) the left and right subtree, it is
called preorder traversal.
So, in a preorder traversal, each node is visited before both of its subtrees.
Algorithm
Example
Now, start applying the preorder traversal on the above tree. First, we traverse the root
node A; after that, move to its left subtree B, which will also be traversed in preorder.
243
So, for left subtree B, first, the root node B is traversed itself; after that, its left
subtree D is traversed. Since node D does not have any children, move to right
subtree E. As node E also does not have any children, the traversal of the left subtree of
root node A is completed.
Now, move towards the right subtree of root node A that is C. So, for right subtree C,
first the root node C has traversed itself; after that, its left subtree F is traversed. Since
node F does not have any children, move to the right subtree G. As node G also does
not have any children, traversal of the right subtree of root node A is completed.
Therefore, all the nodes of the tree are traversed. So, the output of the preorder
traversal of the above tree is -
A→B→D→E→C→F→G
To know more about the preorder traversal in the data structure, you can follow the
link Preorder traversal.
Postorder traversal
This technique follows the 'left-right root' policy. It means that the first left subtree of
the root node is traversed, after that recursively traverses the right subtree, and finally,
the root node is traversed. As the root node is traversed after (or post) the left and right
subtree, it is called postorder traversal.
So, in a postorder traversal, each node is visited after both of its subtrees.
Algorithm
244
Example
Now, start applying the postorder traversal on the above tree. First, we traverse the left
subtree B that will be traversed in postorder. After that, we will traverse the right
subtree C in postorder. And finally, the root node of the above tree, i.e., A, is traversed.
So, for left subtree B, first, its left subtree D is traversed. Since node D does not have any
children, traverse the right subtree E. As node E also does not have any children, move
to the root node B. After traversing node B, the traversal of the left subtree of root node
A is completed.
Now, move towards the right subtree of root node A that is C. So, for right subtree C,
first its left subtree F is traversed. Since node F does not have any children, traverse the
right subtree G. As node G also does not have any children, therefore, finally, the root
node of the right subtree, i.e., C, is traversed. The traversal of the right subtree of root
node A is completed.
At last, traverse the root node of a given tree, i.e., A. After traversing the root node, the
postorder traversal of the given tree is completed.
Therefore, all the nodes of the tree are traversed. So, the output of the postorder
traversal of the above tree is -
D→E→B→F→G→C→A
To know more about the postorder traversal in the data structure, you can follow the
link Postorder traversal.
Inorder traversal
This technique follows the 'left root right' policy. It means that first left subtree is visited
after that root node is traversed, and finally, the right subtree is traversed. As the root
node is traversed between the left and right subtree, it is named inorder traversal.
So, in the inorder traversal, each node is visited in between of its subtrees.
245
The applications of Inorder traversal includes -
Algorithm
Example
Now, start applying the inorder traversal on the above tree. First, we traverse the left
subtree B that will be traversed in inorder. After that, we will traverse the root node A.
And finally, the right subtree C is traversed in inorder.
So, for left subtree B, first, its left subtree D is traversed. Since node D does not have any
children, so after traversing it, node B will be traversed, and at last, right subtree of node
B, that is E, is traversed. Node E also does not have any children; therefore, the traversal
of the left subtree of root node A is completed.
246
At last, move towards the right subtree of root node A that is C. So, for right subtree C;
first, its left subtree F is traversed. Since node F does not have any children, node C will
be traversed, and at last, a right subtree of node C, that is, G, is traversed. Node G also
does not have any children; therefore, the traversal of the right subtree of root node A is
completed.
As all the nodes of the tree are traversed, the inorder traversal of the given tree is
completed. The output of the inorder traversal of the above tree is -
D→B→E→A→F→C→G
To know more about the inorder traversal in data structure, you can follow the
link Inorder Traversal.
The time complexity of tree traversal techniques discussed above is O(n), where 'n' is
the size of binary tree.
Whereas the space complexity of tree traversal techniques discussed above is O(1) if we
do not consider the stack size for function calls. Otherwise, the space complexity of
these techniques is O(h), where 'h' is the tree's height.
247