Data Structure Using C Notes
Data Structure Using C Notes
Structure in C Programming
In C, a structure is a user-defined data type that can be used to group items of possibly
different types into a single type. The struct keyword is used to define a structure. The
items in the structure are called its member and they can be of any valid data type.
#include <stdio.h>
// Defining a structure
struct A {
int x;
};
int main() {
// Creating a structure variable
struct A a;
// Initializing member
a.x = 11;
printf("%d", a.x);
return 0;
}
Output
11
In this example, a structure A is defined to hold an integer member x. A variable a of
type struct A is created and its member x is initialized to 11 by accessing it using dot
operator. The value of a.x is then printed to the console.
Structures are used when you want to store a collection of different data types, such as
integers, floats, or even other structures under a single name.
Syntax of Structure
There are two steps of creating a structure in C:
1. Structure Definition
2. Creating Structure Variables
Structure Definition
A structure is defined using the struct keyword followed by the structure name and its
members. It is also called a structure template or structure prototype, and no memory is
allocated to the structure in the declaration.
struct structure_name {
data_type1 member1;
data_type2 member2;
…
};
Creating Structure Variable
After structure definition, we have to create variable of that structure to use it. It is similar
to the any other type of variable declaration:
struct strcuture_name var;
We can also declare structure variables with structure definition.
Structructure_name {
…
}var1, var2….;
Default Initialization
By default, structure members are not automatically initialized to 0 or NULL. Uninitialized
structure members will contain garbage values. However, when a structure variable is
declared with an initializer, all members not explicitly initialized are zero-initialized.
struct structure_name = {0}; // Both x and y are initialized to 0
Array of Structures in C
An array of structures is simply an array where each element is a structure. It
allows you to store several structures of the same type in a single array.
#include <stdio.h>
#include <string.h>
// Structure definition
struct A {
int var;
};
int main() {
arr[0].var = 10;
arr[1].var = 20;
return 0;
}
Output
10
20
We define a Person structure with name and age as members. An array of 2 Person
structures is declared, and each element is populated with different people’s details. A for
loop is used to iterate through the array and print each person's information.
Array of Structure Declaration
Once you have already defined structure, the array of structure can be defined in a similar
way as any other variable.
struct struct_name arr_name [size];
Need for Array of Structures
Suppose we have 50 employees, and we need to store the data of 50 employees. So for that,
we need to define 50 variables of struct Employee type and store the data within that.
However, declaring and handling the 50 variables is not an easy task. Let's imagine a bigger
scenario, like 1000 employees.
So, if we declare the variable this way, it's not possible to handle this.
struct Employee emp1, emp2, emp3, .. . ... . .. ... emp1000;
For that, we can define an array whose data type will be struct Employee soo that will be
easily manageable.
Arrays of structures allow you to group related data together and handle multiple
instances of that data more efficiently.
It is particularly useful when you want to manage large datasets (such as a list of
employees, students, or products) where each element has a consistent structure.
// Structure definition
struct Student {
char name[50];
int age;
float marks;
};
int main() {
return 0;
}
Output
Student 1:
Name: Nikhil
Age: 20
Marks: 85.50
Student 2:
Name: Shubham
Age: 22
Marks: 90.00
Student 3:
Name: Vivek
Age: 25
Marks: 78.00
Array within Structure in C
An array can be declared inside a structure as a member when we need to store multiple
members of the same type.
For example, suppose we have an employee and we need to store the data of his/her weekly
attendance. So for that, we need to define a structure of type Employee and store the data
within that. However, declaring and handling the 7 variables for each day of the week is not
an easy task.
struct Employee {
int day1, day2, day3, day4, day5, day6, day7;
};
For that, we can define an array within the structure whose data type will be int so that will be
easily manageable.
Note: It is recommended to define the array as the last member function so that if it
overflows, it does not overwrite all the other members.
#include <string.h>
#include <stdio.h>
int main()
{
// defining structure of type Employee
struct Employee emp;
// adding data
emp.employeeID = 1;
strcpy(emp.Name, "Rohit");
int week;
for (week = 0; week < 7; week++) {
int attendence;
emp.WeekAttendence[week] = week;
}
printf("\n");
return 0;
}
Output
Emplyee ID: 1 - Employee Name: Rohit
Attendence
0123456
Array of structures vs array within structure in c
Array within a Structure Array of Structures
A structure contains an array as its member An array in which each element is of type
variable. structure.
struct class { int ar[10]; } a1, a2, a3; struct class { int a, b, c; } students[10];
Can be accessed using the dot operator just Can be accessed by indexing just as we
as we access other elements of the structure. access an array.
Array within the structure will be stored in There will be some empty space between
sequential memory and structure padding is structure elements due to structure padding.
not dependent on the size of the array.
UNIONS
In C, union is a user-defined data type that can contain elements of the different data types
just like structure. But unlike structures, all the members in the C union are stored in the
same memory location. Due to this, only one member can store data at the given point in
time.
Syntax of Union in C
The syntax of union can be defined into two parts:
C Union Declaration
In this part, we only declare the template of the union, i.e., we only declare the members’
names and data types along with the name of the union. No memory is allocated to the
union in the declaration.
union name {
type1 member1;
type2 member2;
.
.
};
Initialize Union
The initialization of a union is the initialization of its members by simply assigning the
value to it.
var1.member1 = val;
One important thing to note here is that only one member can contain some value at a
given instance of time.
int main() {
union A a;
// Storing an integer
a.i = 10;
printf("data.i = %d
", a.i);
// Storing a float
a.f = 220.5;
printf("data.f = %.2f
", a.f);
// Storing a string
strcpy(a.s, "GfG");
printf("data.s = %s
", a.s);
return 0;
}
Output
data.i = 10
data.f = 220.50
data.s = GfG
The size is the sum of the sizes of The size is equal to the size of the
all members, with padding if largest member, with possible
Size necessary. padding.
Data No data overlap as members are Full data overlap as members shares
Overlap independent. the same memory.
Introduction to Pointers in C
A pointer is a variable that stores the memory address of another variable. Instead of
holding a direct value, it holds the address where the value is stored in memory. There are 2
important operators that we will use in pointers concepts i.e.
Dereferencing operator(*) used to declare pointer variable and access the value stored
in the address.
Address operator(&) used to returns the address of a variable or to access the address
of a variable to a pointer.
Example:
#include <stdio.h>
int main()
{
return 0;
}
Output
The Value of Variable m is: 100
The Memory Address of Variable m is: 0x7ffee1eea79c
The Memory Address of Variable m is using ptr: 0x7ffee1eea79c
A. Pointer Declaration
To declare a pointer, we use the (*) dereference operator before its name. In pointer
declaration, we only declare the pointer but do not initialize it.
B. Pointer Initialization
Pointer initialization is the process where we assign some initial value to the pointer
variable. We use the (&) addressof operator to get the memory address of a variable and
then store it in the pointer variable.
Note: We can also declare and initialize the pointer in a single step. This is called pointer
definition.
C. Pointer Dereferencing
Dereferencing a pointer is the process of accessing the value stored in the memory address
specified in the pointer. We use the same (*) dereferencing operator that we used in the
pointer declaration.
Note: It is recommended that the pointers should always be initialized to some value before
starting using it. Otherwise, it may lead to number of errors.
Pointer declaration and initialization
Once you got basics of memory addresses, reference and dereference operator. Let us declare
our first pointer variable.
data-type * pointer-variable-name;
return 0;
}
Output –
Value of num = 1
Address of num = 60ff0c
Value of ptr = 60ff0c
Address of ptr = 60ff08
Value pointed by ptr = 1
After changing value of num directly.
Value of num = 10
Value pointed by ptr = 10
After changing value pointed by ptr.
Value of num = 100
Value pointed by ptr = 100
Accessing a variable through its pointer
Accessing a variable through its pointer involves dereferencing the pointer, which means
accessing the value stored at the memory address pointed to by the pointer.
In this example:
It’s important to note that dereferencing a pointer when it’s not pointing to a valid memory
address (e.g., when it’s uninitialized or pointing to NULL) leads to undefined behavior,
which may result in a segmentation fault or other runtime errors. Always ensure that the
pointer is properly initialized and points to a valid memory location before dereferencing it.
Memory is divided into smaller addressable units called bytes. Assume that these are small
boxes as bytes. Each byte has its own address as per the below table.For example: 0, 1, 2,
3, 4, 5, 6, etc.
The Memory is divided into three sections.
Heap Memory: It is a part of the main memory. It is unorganized and treated as a
resource when you require the use of it if not release. Heap memory can’t be used
directly with the help of a pointer.
Stack Memory: It stores temporary variables created by a function. In stack, variables
are declared, stored, and initialized during runtime. It follows the First in last out
method that means whatever element is going to store last is going to delete first when
it’s not in use.
Code Section: Whenever the program is executed it will be brought into the main
memory. This program will get stored under the code section. Based upon the program
it will decide whether to utilize the stack or heap sections.
In static memory allocation whenever the program executes it fixes the size that the
program is going to take, and it can’t be changed further. So, the exact memory
requirements must be known before. Allocation and deallocation of memory will be done
by the compiler automatically. When everything is done at compile time (or) before run
time, it is called static memory allocation.
Key Features:
Allocation and deallocation are done by the compiler.
It uses a data structures stack for static memory allocation.
Variables get allocated permanently.
No reusability.
Execution is faster than dynamic memory allocation.
Memory is allocated before runtime.
It is less efficient.
C program to illustrate the Static Memory Allocation:
// C program to implement
// static memory allocation
#include <stdio.h>
#include <stdlib.h>
// Driver code
int main()
{
int size;
printf("Enter limit of the text: \n");
scanf("%d", &size);
char str[size];
printf("Enter some text: \n");
scanf(" ");
gets(str);
printf("Inputted text is: %s\n", str);
return 0;
}
Input
a Output:
V Advantages:
Simple usage.
Allocation and deallocation are done by the compiler.
Efficient execution time.
It uses stack data structures .
Disadvantages:
Memory wastage problem.
Exact memory requirements must be known.
Memory can’t be resized once after initialization.
In Dynamic memory allocation size initialization and allocation are done by the
programmer. It is managed and served with pointers that point to the newly allocated
memory space in an area which we call the heap. Heap memory is unorganized and it is
treated as a resource when you require the use of it if not release it. When everything is
done during run time or execution time it is known as Dynamic memory allocation.
Key Features:
Dynamic allocated at runtime
We can also reallocate memory size if needed.
Dynamic Allocation is done at run time.
No memory wastage
There are some functions available in the stdlib.h header which will help to allocate
memory dynamically.
malloc(): The simplest function that allocates memory at runtime is called malloc().
There is a need to specify the number of bytes of memory that are required to be
allocated as the argument returns the address of the first byte of memory that is
allocated because you get an address returned, a pointer is the only place to put it.
Syntax:
int *p = (int*)malloc(No of values*size(int));
The argument to malloc() above clearly indicates that sufficient bytes for accommodating
the number of values of type int should be made available. Also notice the cast (int*),
which converts the address returned by the function to the type pointer to int. malloc()
function returns a pointer with the value NULL.
calloc(): The calloc() function offers a couple of advantages over malloc() . It allocates
memory as a number of elements of a given size. It initializes the memory that is
allocated so that all bytes are zero. calloc() function requires two argument values:
o The number of data items for which space is required.
o Size of each data item.
It is very similar to using malloc() but the big plus is that you know the memory area will
be initialized to zero.
Syntax:
int *p = (int*)calloc(Number of data items, sizeof(int));
realloc(): The realloc() function enables you to reuse or extend the memory that you
previously allocated using malloc() or calloc(). A pointer containing an address that was
previously returned by a call to malloc(), calloc(). The size in bytes of the new memory
that needs to be allocated. It allocates the memory specified by the second argument and
transfers the contents of the previously allocated memory referenced by the pointer
passed as the first argument to the newly allocated memory.
Syntax:
int *np = (type cast) realloc (previous pointer type, new number of elements * sizeof(int));
Syntax:
free(pointer);
For Example:
// C program to illustrate the concept
// of memory allocation
#include <iostream>
using namespace std;
// Driver Code
void main()
{
int* p; // 2 bytes
P = (int*)malloc(5 * sizeof(int));
}
Examples:
In the above piece of code, a pointer p is declared. Assume that pointer p will take 2
bytes of memory and again it depends upon the compiler.
This pointer will store in the stack section and will point to the array address of the first
index which is allocated in the heap. Heap memory cannot be used directly but with the
help of the pointer, it can be accessed.
When the program is not in use, the memory should be deallocated. Otherwise, it will
cause a memory leak.
After deallocating the memory allocated in the heap. Below is the image to illustrate the
main memory after deallocation.
Below is the C program to illustrate the Dynamic Memory Allocation:
C
#include <stdio.h>
#include <stdlib.h>
// Driver Code
int main()
"text: \n");
scanf("%d", &size);
if (str != NULL) {
scanf(" ");
gets(str);
"%s\n",
str);
free(str);
if (str != NULL) {
scanf(" ");
gets(str);
printf("Inputted text by allocating "
"%s\n",
str);
scanf("%d", &resize);
"realloc() \n");
if (str != NULL) {
scanf(" ");
gets(str);
"%s\n",
str);
}
free(str);
str = NULL;
return 0;
Advantages:
Dynamic Allocation is done at run time.
We can allocate (create) additional storage whenever we need them.
Memory can be deallocated (free/delete) dynamic space whenever we are done with
them.
Thus, one can always have exactly the amount of space required – no more, no less.
Memory size can be reallocated if needed.
Disadvantages:
As the memory is allocated during runtime, it requires more time.
Memory needs to be freed by the user when done. This is important as it is more likely
to turn into bugs that are difficult to find.
Differences between Static and Dynamic memory allocation
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.
1. Primitive Data Structures: They store the data of only one type i.e. built-in data
types. Data types like integer, float, character, and booleans come in this category.
2. Non-Primitive Data Structures: They can store the data of more than one type
i.e. derived data types. Data types like arrays, linked lists, trees, etc. come in this
category. Non-Primitive Data Structures are data structures derived from Primitive
Data Structures.
Based on the structure and arrangement of data, these data structures are further
divided into two categories
Simple: They represent simple values and are not derived from other data structures.
Predefined: They are predefined in most programming languages and are handled
directly by the machine's CPU.
Efficient: They offer simple operations and are memory-efficient because they
directly store the data.
1. Integer
2. Float (or Double)
3. Character (Char)
4. Boolean
6. Pointers
1. Integer
An Integer data type that represents whole numbers, both positive and negative, without any
fractional part.
Example: int a = 5;
Operations: Arithmetic operations like addition, subtraction, multiplication, division.
A Float data type is used to represent numbers with fractional parts (decimals).
Example: float b = 5.75;
Operations: Arithmetic operations, rounding, and truncation.
3. Character (Char)
4. Boolean
5. String
Pointers are variables that store the memory address of another variable.
Efficiency: Since they are simple and directly supported by hardware, they are fast
and efficient in terms of memory and processing power.
Ease of Use: Simple and easy to understand as they don’t involve complex
relationships between elements.
Fixed Size: Their size is usually fixed, leading to predictable memory usage.
Limited Functionality: As they represent basic data types, they don’t support
complex structures or operations.
No Relationships: They do not allow representation of relationships between data,
unlike complex data structures (like arrays or trees).
1. Arrays
An array is a collection of elements, all of the same data type, stored in contiguous memory
locations. It has a fixed size, which is specified during its creation.
Characteristics:
Applications: Used to store data in a database, matrices, and images (in terms of pixels).
Operations:
2. Linked Lists
A linked list is a collection of nodes, where each node stores a data element and a reference
(pointer) to the next node in the sequence. It is a dynamic data structure with no fixed size.
Characteristics:
Advantages: Dynamic size allows for efficient memory usage. Insertions and deletions are
efficient at both ends (front or back).
Disadvantages: Sequential access (no direct access to elements by index). Extra memory is
required for storing pointers
3 Stacks
A stack is a linear data structure that follows the Last-In-First-Out (LIFO) principle, where
the last element added is the first one to be removed.
Characteristics:
Only two operations are allowed: push (add an element to the top) and pop (remove
the top element).
Advantages: Simple and fast for certain tasks like undo operations and parsing expressions.
Disadvantages: Limited access to other elements (only the top element is accessible). Fixed-
size in an array-based implementation.
4. Queues
A queue is a linear data structure that follows the First-In-First-Out (FIFO) principle, where
the first element added is the first one to be removed.
R
N 0;
Operates with two main pointers: front (removes elements) and rear (adds elements).
Efficient for processing tasks in order.
Applications: CPU scheduling, printer task scheduling, handling requests in web servers.
Operations:
Read More: Queue in Data Structures - Types & Algorithm (With Example)
Definition: A deque is a linear data structure that allows elements to be added or removed
from both ends (front and rear).
Characteristics:
1. Trees
A tree is a hierarchical structure that consists of nodes, with each node containing data and
references to its child nodes. The topmost node is called the root, and each node can have
zero or more child nodes.
Characteristics:
Advantages: Efficient searching and sorting (in balanced trees like AVL trees and red-black
trees).
Disadvantages: Complex implementation, especially for balanced trees.
2. Graphs
A graph is a collection of nodes (vertices) and edges, where edges represent the relationships
between nodes. Graphs can be directed or undirected.
Characteristics:
Applications: Social networks (users and their connections), shortest path problems (e.g.,
Dijkstra's algorithm), web page linking (web graphs).
Operations:
Add/Remove Vertices and Edges: Modify the structure of the graph.
Traversal: Visit all nodes via BFS (Breadth-First Search) or DFS (Depth-First
Search).
Arrangement of The data is consecutively stored one after the The data is stored in a non-sequential
data other. (hierarchical) manner.
Each data stored is directly linked to its The data is stored in a random manner or
Storage of data
previous and next elements. contiguous memory locations.
Layers of data The data is arranged in a single layer. The data is arranged in multiple layers.
The time required to access all the data in the The time required to access all the data in the
Time
data structure increases as the volume of the data structure remains the same even if the
complexity
data increases. volume of the data increases.
Number of The user can traverse the data structure in a The user cannot traverse the data structure in a
traverses single pass. single pass.
Irrespective of the volume of the data, these Irrespective of the volume of the data, these
Advantages data structures are easy to use where the data structures are easy to use where the
operations are simple. operations are complex.
Linear data structures are widely used in Non-linear data structures are widely used in
Uses
software development. Artificial intelligence, image processing, etc.
Data structure operations are the methods used to manipulate the data in a data structure. The
most common data structure operations are:
Traversal
raversal operations are used to visit each node in a data structure in a specific order.
T
This technique is typically employed for printing, searching, displaying, and reading
the data stored in a data structure.
Insertion
I nsertion operations add new data elements to a data structure. You can do this at the
data structure's beginning, middle, or end.
Deletion
eletion operations remove data elements from a data structure. These operations are
D
typically performed on nodes that are no longer needed.
Search
earch operations are used to find a specific data element in a data structure. These
S
operations typically employ a compare function to determine if two data elements are
equal.
Sort
ort operations are used to arrange the data elements in a data structure in a specific
S
order. This can be done using various sorting algorithms, such as insertion sort,
bubble sort, merge sort, and quick sort.
Merge
erge operations are used to combine two data structures into one. This operation is
M
typically used when two data structures need to be combined into a single structure.
Copy
opy operations are used to create a duplicate of a data structure. This can be done by
C
copying each element in the original data structure to the new one.
X AND REVIEW OF AN ARRAY
Array in C is one of the most used data structures in C programming. It is a simple and fast
way of storing multiple values under a single name. In this article, we will study the
different aspects of array in C language such as array declaration, definition, initialization,
types of arrays, array syntax, advantages and disadvantages, and many more.
What is Array in C?
An array in C is a fixed-size collection of similar data items stored in contiguous memory
locations. It can be used to store the collection of primitive data types such as int, char,
float, etc., and also derived and user-defined data types such as pointers, structure,
C Array Declaration
In C, we have to declare the array like any other variable before using it. We can declare an
array by specifying its name, the type of its elements, and the size of its dimensions. When
we declare an array in C, the compiler allocates the memory block of the specified size to
the array name.
Syntax of Array Declaration
data_type array_name [size];
or
data_type array_name [size1] [size2]...[sizeN];
where N is the number of dimensions.
The C arrays are static in nature, i.e., they are allocated memory at the compile
time.
Example of Array Declaration
// declaring array of integers
int arr_int[5];
O HOMEPAGE
O CONTACT US
O ABOUT US
O