Introduction to Data Structures
Introduction to Data Structures
A data structure is a specialized format for organizing, managing, and storing data
efficiently. It defines the way data is stored, accessed, and manipulated in a program.
The choice of a data structure affects the efficiency of algorithms and the overall
performance of a program.
INTRODUCTION
An array is a group of related data items that share a common name. For instance, we
can define an array name salary to represent a set of salaries of a group of employees.
o salary[10]
o represents the salary of the 10th employee.
While the complete set of values is referred to as an array, the individual values are
called elements. Arrays can be of any variable type.
The ability to use a single name to represent a collection of items and to refer to an
item by specifying the item number enables us to develop concise and efficient
programs. For example, a loop with the subscript as the control variable can be used
to read the entire array, perform calculations and, print out the results.
ONE-DIMENSIONAL ARRAYS
A list of items can be given one variable name using only one subscript and such a
variable is called single-subscripted variable or a one-dimensional array.
Declaration of Arrays
Like any other variable, arrays must be declared before they are used. The general
form of array declaration is
type variable-name[size];
The type specifies the type of element that will be contained in the array, such as int,
float, or char and the size indicates the maximum number of elements that can be
stored inside the array. For example,
float height[50];
declares the height to be an array containing 50 real elements. Any subscripts 0 to 49
are valid. Similarly,
int group[10];
declares the group as an array to contain a maximum of 10 integer constants.
Remember, any reference to the arrays outside the declared limits would not
necessarily cause an error. Rather, it might result in unpredictable program results.
The C language treats character strings simply as arrays of characters. The size in a
character string represents the maximum number of characters that the string can
hold. For instance,
char name[10];
declares the name as a character array (string) variable that can hold a maximum of 10
characters.Suppose we read the following string constant into the string variable
name.
“WELL DONE”
Each character of the string is treated as an element of the array name and is stored in
the memory as follows:
When the compiler sees a character string, it terminates it with an additional null
character. Thus, the element name[9] holds the null character \0 at the end. When
declaring character arrays, we must always allow one extra element space for the null
terminator.
Initialization of Arrays
We can initialize the elements of arrays in the same way as the ordinary variables
when they are declared.
The general form of initialization of arrays is:
static type array-name[size] = { list of values };
The values in the list are separated by commas. For example, the statement
static int number[3] = { 0,0,0 };
will declare the variable number as an array of size 3 and will assign zero to each
element. If the number of values in the list is less than the number of elements, then
only that many elements will be initialized. The remaining elements will be set to zero
automatically. For instance,
static float total[5] = {0.0,15.75, 10};
will initialize the first three elements to 0.0, 15.75, and 10.0 and the remaining two
elements to zero.
For example, the statement
static int counter[ ] = {1,1,1,1};
will declare the counter array to contain four elements with initial values 1. This
approach works fine as long as we initialize every element in the array.
Character arrays may be initialized in a similar manner. Thus, the statement
char name[ ] = {‘J’, ‘o’, ‘h’, ‘n’};
declares the name to be an array of four characters, initialized with the string “John”.
Initialization of arrays in C suffers two drawbacks.
There is no convenient way to initialize only selected elements.
There is no shortcut method for initializing a large number of array elements like the
one available in FORTRAN.
Consider the following data table, which shows the value of the sales of three items
by four salesgirls:
The table contains a total of 12 values, three in each line. We can think of this table as
a matrix consisting of four rows and three columns. Each row represents the values of
sales by a particular salesgirl and each column represents the values of sales of a
particular item.
In mathematics, we represent a particular value in a matrix by using two subscripts
such as vij. Here v denotes the entire matrix and vij refers to the value in the ith row
and jth column. For example, in the above table v23 refers to the value 325.
C allows us to define such tables of items by using two-dimensional arrays. The table
discussed above can be defined in C as
v[4][3]
Two-dimensional arrays are declared as follows:
type array_name [row_size][column_size];
Prog
rams:
Example 8.1:
Write a program using a single-subscripted variable to evaluate the following
expressions/sum of squares of numbers.
#include <stdio.h>
int main() {
int i;
float x[10], total = 0.0;
scanf("%f", &x[i]);
return 0;
}
Output:
Example 8.2
43 65 51 27 79 11 56 61 82 09
25 36 07 49 55 63 74 81 49 37
40 49 16 75 87 91 33 24 58 78
65 56 76 67 45 54 36 63 12 21
73 49 51 19 39 49 68 93 85 59
Write a program to count the number of students belonging to each of the following
groups of marks:
#include <stdio.h>
#define MAXVAL 50
#define COUNTER 11
int main() {
float value[MAXVAL] = {
40, 49, 16, 75, 87, 91, 33, 24, 58, 78,
65, 56, 76, 67, 45, 54, 36, 63, 12, 21,
};
++group[index];
low = i * 10;
return 0;
Output:
Example 8.3
Program:
#include <stdio.h>
#define MAXGIRLS 4
#define MAXITEMS 3
int main() {
int value[MAXGIRLS][MAXITEMS];
int i, j, grand_total;
girl_total[i] = 0;
scanf("%d", &value[i][j]);
girl_total[i] += value[i][j];
/* Computing item_total */
item_total[j] = 0;
item_total[j] += value[i][j];
/* Computing grand_total */
grand_total = 0;
grand_total += girl_total[i];
}
/* Printing results */
printf("\nGIRLS TOTALS\n\n");
printf("\nITEM TOTALS\n\n");
return 0;
}
#include <stdio.h>
#define ROWS 5
#define COLUMNS 5
int main() {
int i, j;
printf("MULTIPLICATION TABLE\n\n");
printf(" ");
printf("%4d", j);
printf("\n");
printf(" ---------------------\n");
row = i + 1;
column = j + 1;
product[i][j] = row * column;
printf("\n");
return 0;
Pointers
The basic data types in C language are int, float, char, double and void. Pointer is a
special data type which is derived from these basic data types, So, pointer is called
derived data type. The pointer takes the values from 0 to 65535 if the size of the RAM
is 64K.
Pointer concepts
-pointer constants
-pointer values
-pointer variables
= 64 x 1024 bytes
= 65536 locations
Logically, all 65536 locations in computer memory are numbered sequentially from 0 to
65535 but, physically they are divided into even bank and odd bank. Even bank is set of
memory locations with even addresses and odd bank is set of memory locations with odd
addresses as shown below:
These memory addresses are called pointer constants. We can not change them; but, we can
only use them to store data values.
For example, in the above memory organization, the addresses ranging from 0 to 65535 are
pointer constants.
Note: The address of a memory location is a pointer constant and can not be changed.
• Store 100, 200 and 300 at the locations i, j and k respectively as shown below:
The address of the variable can not be accessed directly. The address of the variable
can be obtained using address operator (denoted by &) in C language.
Note: The address operator can be used with any variable that can be placed on the left side
of an assignment operator. Since constants, expressions and array names can not be used on
the left hand side of the assignment and hence accessing address is invalid for constants,
expressions and array names. The following are invalid:
Definition: Memory is divided into number of storage cells called locations. All the locations
in computer memory are numbered sequentially from 0 to 65535 (with memory size of 64K).
Out of these addresses, the system assigns some addresses of the memory locations to
the variables. These memory addresses assigned to variables by the system are called
pointer values.
For example, the addresses 65530, 65532 and 65534 which are assigned to the
variables i, j and k are pointer values. These pointer values can be obtained using
address operator (&). Using &i, &j and &k we can obtain pointer values 65530,
65532 and 65534.
Note: Without address operator (&), it is not possible to obtain the pointer value of a
variable.
Note: The pointer values (i.e., the addresses assigned to variables) may vary each time the
program is executed. That is, the address of the variable may change from one run of the
program to another.
Definition: A variable which holds address of another variable is called <pointer variable. In
other words, pointer variable is a variable which holds pointer value (i.e., address of a
variable). For example, if i is a variable and address of i is stored in a variable p as shown
below:
p=&i;
then the variable p is called a pointer variable. The memory organization after executing the
above statement is shown below:
int *p;
This indicates that p is a pointer variable and the corresponding memory location should
contain address of an integer variable. But, the declaration will not initialize the memory
location and memory contains garbage value as shown below:
Deflnitione e, pointer variable should contain a valid address. A pointer variable which does
not contain a valid address is called dangling pointer.
A NULL pointer is defined as a special pointer value that points to nowhere in the
memory. If it is too early in the code to assign a value to the pointer,then it is better to
assign NULL (i.e., \0 or 0) to the pointer.
For example, consider the following code:
#include <stdio.h>
int *p = NULL;
Here, the pointer variable p is a NULL pointer. This indicates that the pointer
variable p does not point to any part of the memory. The value for NULL is defined in
the header file "stdio.h". Instead of using NULL we can also use '\0' or O.
The programmer can access the data using the pointer variable p if and only it does
not contain NULL. The error condition can be checked using the following statement:
if (p = = NULL)
printf("p does not point to any memory]n");
printf("Access the value of p\n");
else {
…..
}
Note: By specifying *p, the value of the variable whose address is stored in p can be
accessed. Here, p should be a pointer variable.
2.5 Pointer applications
This function allows the program to allocate memory explicitly as and when
required and the exact amount needed during execution. This function
allocates a block of memory. The size of the block is the number of bytes
specified in the parameter. The syntax is shown below:
where
• ptr is a pointer variable of type data_type
• data_type can be any of the basic data type or user defined data type
• On successful allocation, the function returns the address of first byte of allocated memory.
Since address is returned, the return type is a void pointer. By type casting appropriately we
can use it to store integer, float etc.
• If specified size of memory is not available, the condition is called "overflow of memory".
In such case, the function returns NULL.
void function_name()
if (ptr = NULL)
printf("Insufficient memory\n");
exit(0);
}
calloc{n, size)
where
• data_type can be any of the basic data type or user defined data type
On successful allocation, the function returns the address of first byte of allocated
memory. Since address is returned, the return type is a void pointer. By type casting
appropriately we can use it to store integer, float etc.
"If specified size of memory is not available, the condition is called "overflow of
memory". In such case, the function returns NULL.
void function_name()
{
ptr = (data_type *) calloc(size);
if (ptr = NULL)
{
printf("Insufficient memory\n");
exit(0);
}
}
realloc(ptr, size)
Before using this function, the memory should have been allocated using malloc() or
calloc(). Sometimes, the allocated memory may not be sufficient and we may require
additional memory space. Sometimes, the allocated memory may be much larger and
we want to reduce the size of allocated memory.
In both situations, the size of allocated memory can be changed using realloc() and
the process is called reallocation of memory. The reallocation is done as shown
below:
• realloc() changes the size of the block by extending or deleting the memory at the end of the
block.
• If the existing memory can be extended, ptr value will not be changed,If the memory can
not be extended, this function allocates a completely new block and copies the contents of
existing memory block into new memory block and then deletes the old memory block. The
syntax is shown below:
where
malloct) or calloct).
if (ptr == NULL)
Printf(“Insufficient memory\n");
return;
}
free(ptr)
This function is used to de-allocate (or free) the allocated block of memory which is
allocated by using the functions calloc(), malloc() or realloc(). It is the responsibility a
programmer to de-allocate memory whenever it is not required by the program and
initialize ptr to NULL. The syntax is shown below:
free(ptr);
ptr =NULL;
struct book_bank
char title[20];
char author[15];
int pages;
float price;
};
The keyword struct declares a structure to hold the details of four fields, namely title,
author, pages,and price. These fields are called structure elements or members. Each
member may belong to a different type of data. book_bank is the name of the
structure and is called the structure tag. The tag name may be used subsequently to
declare variables that have the tag’s structure.
We can declare structure variables using the tag name anywhere in the program. For
example, the statement
struct book_bank book1, book2, book3;
Each one of these variables has four members as specified by the template. The complete
declaration might look like this:
struct book_bank
char title[20];
char author[15];
int pages;
float price;
};
Remember that the members of a structure themselves are not variables. They do not occupy
any memory until they are associated with the structure variables such as book1.
for its name and type in a separate statement inside the template.
3. The tag name such as book_bank can be used to declare structure variables of its type, later
in the program.
It is also allowed to combine both the template declaration and variables declaration in one
statement.
The declaration
struct book_bank
{
char title[20];
char author[15];
int pages;
float price;
struct
........
........
........
declares book1, book2, and book3 as structure variables representing three books, but does
not include a tag name for later use in declarations.
Normally, structure definitions appear at the beginning of the program file, before any
variables or functions are defined. They may also appear before the main, along with
macro definitions, such as #define. In such cases, the definition is global and can be
used by other functions as well.
STRUCTURE INITIALIZATION
main( )
static struct
int weight;
float height;
.....
.....
main( )
{
struct st_record
int weight;
float height;
};
.....
.....
Another method is to initialize a structure variable outside the function as shown below:
int weight,
float height;
main( )
.....
.....
}
COMPARISON OF STRUCTURE VARIABLES
Two variables of the same structure type can be compared the same way as ordinary
variables. If
person1 and person2 belong to the same structure, then the following operations are valid:
ARRAYS OF STRUCTURES
defines an array called student, that consists of 100 elements. Each element is defined to be of
the type struct class. Consider the following declaration:
struct marks
int subject1;
int subject2;
int subject3;
};
main( )
This declares the student as an array of three elements student[0], student[1], and student[2]
and
student[0].subject1 = 45;
student[0].subject2 = 68;
. . . ..
. . . ..
student[2].subject3 = 71;
struct marks
int number;
float subject[3];
} student[2];
Here, the member subject contains three elements, subject[0], subject[1] and subject[2].
These
elements can be accessed using appropriate subscripts. For example, the name
student[1].subject[2];
would refer to the marks obtained in the third subject by the second student.
struct salary
char name[20];
char department[10];
int basic_pay;
int dearness_allowance;
int house_rent_allowance;
int city_allowance;
employee;
This structure defines name, department, basic pay and three kinds of allowances. We can
group all the items related to allowance together and declare them under a substructure as
shown below:
struct salary
char name[2];
char department[10];
struct
int dearness;
int house_rent;
int city;
allowance;
employee;
The salary structure contains a member named allowance which itself is a structure
with three members.
The members contained in the inner structure namely dearness, house_rent, and city
can be referred to as
employee.allowance.dearness
employee.allowance.house_rent
employee.allowance.city
UNIONS
Unions are a concept borrowed from structures and therefore follow the same syntax
as structures.
However, there is major distinction between them in terms of storage. In structures,
each member has its
own storage location, whereas all the members of a union use the same location. This
implies that,
although a union may contain many members of different types, it can handle only
one member at a time.
Like structures, a union can be declared using the keyword union as follows:
union item
{
int m;
float x;
char c;
} code;
This declares a variable code of type union item. The union contains three members,
each with a
different data type. However, we can use only one of them at a time. This is due to the
fact that only one
location is allocated for a union variable, irrespective of its size.
To access a union member, we can use the same syntax that we use for structure
members. That is,
code.m
code.x
code.c
are all valid member variables. During accessing, we should make sure that we are accessing
the member whose value is currently stored. For example, the statements such as
code.m = 379;
code.x = 7859.36;
printf(“%d”, code.m);
In effect, a union creates a storage location that can be used by any one of its
members at a time. When a different member is assigned a new value, the new value
supercedes the previous member’s value.
Unions may be used in all places where a structure is allowed. The notation for
accessing a union member which is nested inside a structure remains the same as for
the nested structures.
typedef
C provides the typedef keyword that allows you to specify a new name for a data type
already provided in the C programming language. In other words, you can use the
typedef keyword to specify an identifier for an existing data type. The declaration for
the typedef keyword is:
In the above example, data type represents the existing data type for which you want to
specify an
example:
Here, int is the data type available in C and a new identifier num has been specified for this
data type.
The following code shows an example for using the typedef keyword:
#include <stdio.h>
#include <conio.h>
int main(void)
num a, b, add;
a=10;
b=20;
add=0;
add = a+b;
clrscr();
getch();
return 0;
SIZE OF STRUCTURES
We normally use structures, unions, and arrays to create variables of large sizes. The
actual size of these variables in terms of bytes may change from machine to machine.
We may use the unary operator sizeof to tell us the size of a structure (or any
variable). The expression
sizeof (struct x)
will evaluate the number of bytes required to hold all the members of the structure x. If y is a
simple
sizeof(y)
would also give the same answer. However, if y is an array variable of type struct x, then
sizeof(y)
size of(y)/sizeof(x)
Programs on Structures:
Define a structure type, struct personal, that would contain person name, date of joining
and salary. Using this structure, write a program to read this information for one
person from the keyboard and print the same on the screen.
#include <stdio.h>
struct personal {
char name[20];
int day;
char month[10];
int year;
float salary;
};
int main() {
person.name,
&person.day,
person.month,
&person.year,
&person.salary);
person.day,
person.month,
person.year,
person.salary);
return 0;
Output:
#include <stdio.h>
#include <string.h>
struct person {
char name[20];
int age;
float salary;
};
int main() {
} else {
return 0;
Output:
For the student array discussed above, write a program to calculate the subjectwise and
studentwise totals and store them as a part of the structure.
#include <stdio.h>
struct marks {
int sub1;
int sub2;
int sub3;
int total;
};
int main() {
int i;
};
total.sub1 += student[i].sub1;
total.sub2 += student[i].sub2;
total.sub3 += student[i].sub3;
total.total += student[i].total;
}
// Display student-wise totals
printf("STUDENT TOTAL\n\n");
printf("\nSUBJECT TOTAL\n\n");
return 0;
Output: