DS NotesNLab2
DS NotesNLab2
problems, the task will be much easier i.e., divide, conquer and
combine. A complex problem usually cannot be divided and
organized. This is because when we divide the big problems into sub
a particular structure (or data structure) for the data items, certain
Non-linear data structure is a kind of random type of data structure. The non-
linear data structures are Tree and Graph.
Primitive data structure will contain Non-primitive data structure can consist
some value, i.e., it cannot be NULL. of a NULL value.
The size depends on the type of the In case of non-primitive data structure,
data structure. size is not fixed.
Primitive data structure is a data structure that can hold a single value in a
specific location whereas the non-linear data structure can hold multiple values
either in a contiguous location or random locations
The examples of primitive data structure are float, character, integer and pointer.
The value to the primitive data structure is provided by the programmer. The
following are the four primitive data structures:
Integer: The integer data type contains the numeric values. It contains the whole
numbers that can be either negative or positive. When the range of integer data
type is not large enough then in that case, we can use long.
Float: The float is a data type that can hold decimal values. When the precision of
decimal value increases then the Double data type is used.
Boolean: It is a data type that can hold either a True or a False value. It is mainly
used for checking the condition.Character: It is a data type that can hold a single
character value both uppercase and lowercase such as 'A' or 'a'.
In case of linear data structure, the data is stored in a sequence, i.e., one data
after another data. When we access the data from the linear data structure, we
just need to start from one place and will find other data in a sequence.
o Array: An array is a data structure that can hold the elements of same type.
It cannot contain the elements of different types like integer with character.
The commonly used operation in an array is insertion, deletion, traversing,
searching.
For example:
The above example is an array that contains the integer type elements stored in a
contiguous manner.
In the above example, the length of the string is 17 as the last character is the
NULL character which denotes the termination of the string.
Char Representation:
1. char name[100] = {'H', 'e', 'l','l','o',' ', 'j', 'a', 'v', 'a', 't','p', 'o', 'i', 'n', 't' }
In the above example, the length of the string is 16 as it does not have any NULL
character as the last character to denote the termination.
o Stack: Stack is a data structure that follows the principle LIFO (Last In First
Out). All the operations on the stack are performed from the top of the
stack such as PUSH and POP operation. The push operation is the process
of inserting element into the stack while the pop operation is the process
of removing element from the stack. The stack data structure can be
implemented by using either array or linked list.
o Queue: Queue is a data structure that can be implemented by using array.
The difference between the stack and queue data structure is that the
elements in the queue are inserted from the rear end while the elements in
the queue are removed from the front end.
Introduction to C Pointers
A Pointer in C language is a variable that holds a memory address. This
memory address is the address of another variable (mostly) of same data
type.
In simple words, if one variable stores the address of second variable then
the first variable can be said to point towards the second variable.
Before we start understanding what pointers are and what they can do, let's
start by understanding what does "Address of a memory
location" means?
If var is the name of the variable, then &var will give it's address.
Let's write a small program to see memory address of any variable that we
define in our program.
#include<stdio.h>
void main()
int var = 7;
Also while using the scanf() function, we mention &var to take user input
for any variable var.
scanf("%d", &var);
Copy
This is used to store the user input value to the memory address of the
variable var.
What is a Pointer in C?
Pointers are used to access memory of a variable and manipulate the value
stored in it.
Pointers are one of the most distinct and exciting
features of C language. It provides power and flexibility
to the language. Although pointers may appear a little
confusing and complicated in the beginning, but trust
me, once you understand the concept, you will be able
to do so much more with C language.
We can access the value 10 either by using the variable name a or by using
its address 80F.
The question is how we can access a variable using it's address? Since the
memory addresses are also just numbers, they can also be assigned to
some other variable. The variables which are used to hold memory
addresses are called Pointer variables.
A pointer variable is therefore nothing but a variable which holds an
address of some other variable. And the value of a pointer
variable gets stored in another memory location.
Pointer Variable in C
Like we mentioned above that a pointer is also a variable, but with a little
twist, that is, it only stores address of other variables.
type *name;
Copy
Here, type is the data type of the pointer, and the name is the
name of the pointer variable.
And the * operator with the name, informs the compiler that
the variable is a pointer.
1. * operator
2. & operator
We have covered operators in C in detail separately.
The & operator returns the memory address of its operand. For
example,
a = &b;
Copy
c = *a;
Copy
Pointers in C Example
Let's see a basic code example where we will create a pointer and assign it
a value.
#include<stdio.h>
int main(void)
int x = 99;
// declare a pointer
int *ptr;
ptr = &x;
return 0;
Copy
type *pointer_name;
Copy
Here, pointer_name is the name of the pointer and that should be a valid C
identifier.
The datatype of the pointer and the variable to which the pointer variable is
pointing must be the same.
Copy
Just like a variable, pointer is declared in the same way, just with an
additional pointer operator *.
#include<stdio.h>
int main(void)
int a = 10;
// declare a pointer
int *ptr;
ptr = &a;
return 0;
Copy
For example, if we have a float type variable and an int type pointer, then C
compiler will give error.
#include<stdio.h>
int main(void)
float a = 10;
// declare a pointer
int *ptr;
ptr = &a;
return 0;
Copy
When we assign NULL to a pointer, it means that it does not point to any
valid address. NULL denotes the value 'zero'.
int *ptr = 0;
Copy
The above code will initialize the ptr pointer will a null value.
#include<stdio.h>
int main(void)
float a = 10;
p1 = &a;
p2 = p1;
return 0;
1. void * pointer
Let's see how we can use explicit cast for pointer conversion.
#include<stdio.h>
int main(void)
double a = 1000.10;
double b;
// declare a pointer
int *p1;
p1 = (int *) &a;
b = *p1;
printf("Value of a is: %f \n", b);
return 0;
Copy
Derefrencing Pointer in C
Once a pointer has been assigned the address of a variable, the pointer
is dereferenced, using the indirection operator or dereferencing
operator, which is a *, to access the value of the variable.
int a = 5;
float b = 5.5;
// *ptr1 = 2 is equivalent to a = 2
#include <stdio.h>
int main()
int a;
a = 10;
printf("%d\n", *p);
printf("%d\n", *&a);
printf("%u\n", &a);
printf("%u\n", p);
return 0;
10
10
3795480300
3795480300
3795480304
Points to Remember while using Pointers
#include <stdio.h>
int **p1;
#include <stdio.h>
int main() {
int a = 10;
int **p2;
/*
*/
p1 = &a;
p2 = &p1;
printf("Address of a = %u\n", &a);
/*
p2 = &a;
printf("%u", p2);
*/
return 0;
Address of a = 2686724
Address of p1 = 2686728
Address of p2 = 2686732
Value of **p2 = 10
• **p2 can be read as *(*p2). Hence, it gives us the value stored at the
address *p2. From above statement, you know *p2 means the address
of variable a. Hence, the value at the address *p2 is 10.
Thus, **p2 prints 10.
int arr[5] = { 1, 2, 3, 4, 5 };
Copy
Suppose the base address of arr is 1000 and each integer requires two
bytes, the five elements will be stored as follows:
Variable arr will give the base address, which is a constant pointer pointing
to arr[0]. Hence arr contains the address of arr[0] i.e 1000.
arr has two purpose -
NOTE:
Pointer to Array
Use a pointer to an array, and then use that pointer to access the array
elements. For example,
#include<stdio.h>
void main()
int *p = a;
printf("%d", *p);
p++;
return 0;
}
Copy
1 2 3
Syntax:
Copy
is same as:
a[i]
Pointer to Multidimensional Array
Syntax:
*(*(a + i) + j)
Copy
Pointer is used to create strings. Pointer variables of char type are treated as
string.
Copy
The above code creates a string and stores its address in the pointer
variable str. The pointer str now points to the first character of the string
"Hello".
char *str;
str = "hello";
Copy
• The content of the string can be printed using printf() and puts().
printf("%s", str);
puts(str);
Copy
• str is a pointer to the string and also name of the string. Therefore we
do not need to use indirection operator *.
Array of Pointers
Pointers are very helpful in handling character arrays with rows of varying
lengths.
char *name[3] = {
"Adam",
"chris",
"Deniel"
};
//without pointer
char name[3][20] = {
"Adam",
"chris",
"Deniel"
};
Copy
In the second approach memory wastage is more, hence it is preferred to
use pointer in such cases.
#include <stdio.h>
struct Book
char name[10];
int price;
}
int main()
ptr = &a;
p = &b;
return 0;
}
Accessing Structure Members with Pointer
#include <stdio.h>
struct my_structure {
char name[20];
int number;
int rank;
};
int main()
ptr = &variable;
return 0;
Copy
NAME: StudyTonight
NUMBER: 35
RANK: 1
Pointer Arithmetic in C
16 bit Machine (Turbo C)
In a 16 bit machine, size of all types of pointer, be it int*, float*, char* or double* is
always 2 bytes. But when we perform any arithmetic function like
increment on a pointer, changes occur as per the size of their primitive data
type.
char 1
long 4
float 4
double 8
long double 10
Now lets take a few examples and understand this more clearly.
int* i;
i++;
Copy
In the above case, pointer will be of 2 bytes. And when we increment it, it
will increment by 2 bytes because int is also of 2 bytes.
float* i;
i++;
In this case, size of pointer is still 2 bytes initially. But now, when we
increment it, it will increment by 4 bytes because float datatype is of 4 bytes.
double* i;
i++;
Copy
Similarly, in this case, size of pointer is still 2 bytes. But now, when we
increment it, it will increment by 8 bytes because its data type is double.
The concept of pointer arithmetic remains exact same, but the size of
pointer and various datatypes is different in a 32 bit machine. Pointer in 32
bit machine is of 4 bytes.
char 2
long 8
float 8
double 16
But we can subtract two pointers. This is because difference between two
pointers gives the number of elements of its data type that can be stored
between the two pointers.
#include <stdio.h>
int main()
int m = 5, n = 10, o = 0;
int *p1;
int *p2;
int *p3;
o = *p1+*p2;
p3 = p1-p2;
p1++;
p2--;
return 0;
Copy
p1 = 2680016
p2 = 2680012
*p1+*p2 = 15
p1-p2 = 1
p1++ = 2680020
p2-- = 2680008
1. Point 1: Here, * means 'value at the given address'. Thus, it adds the
value of m and n which is 15.
int main()
printf("After Swapping:\n\n");
return 0;
/*
*/
int temp;
temp = *a;
*a = *b;
*b = temp;
Copy
m = 10
n = 20tt
After Swapping:
m = 20
n = 10
A function can also return a pointer to the calling function. In this case you
must be careful, because local variables of function doesn't live outside the
function. They have scope only inside the function. Hence if you return a
pointer connected to a local variable, that pointer will be pointing to
nothing when the function ends.
#include <stdio.h>
void main()
int a = 15;
int b = 92;
int *p;
p = larger(&a, &b);
printf("%d is larger",*p);
return x;
else
return y;
92 is larger
2. Or, use static local variables inside the function and return them. As
static variables have a lifetime until the main() function exits, therefore
they will be available througout the program.
Pointer to functions
type (*pointer-name)(parameter);
Copy
Here is an example :
Copy
s = sum;
Copy
Here s is a pointer to a function sum. Now sum can be called using function
pointer s along with providing the required argument values.
s (10, 20);
return x+y;
int main( )
fp = sum;
return 0;
25
It appears complex but it is very simple. In this case (*foo) is a pointer to the
function, whose argument is of int* type and return type is void*.
Dynamic memory allocation in C
1. malloc()
2. calloc()
3. realloc()
4. free()
Now let's have a quick look at the methods used for dynamic
memory allocation.
malloc() function in C
1. ptr=(cast-type*)malloc(byte-size)
1. #include<stdio.h>
2. #include<stdlib.h>
3. int main(){
4. int n,i,*ptr,sum=0;
5. printf("Enter number of elements: ");
6. scanf("%d",&n);
7. ptr=(int*)malloc(n*sizeof(int)); //memory allocated u
sing malloc
8. if(ptr==NULL)
9. {
10. printf("Sorry! unable to allocate memory");
11. exit(0);
12. }
13. printf("Enter elements of array: ");
14. for(i=0;i<n;++i)
15. {
16. scanf("%d",ptr+i);
17. sum+=*(ptr+i);
18. }
19. printf("Sum=%d",sum);
20. free(ptr);
21. return 0;
22. }
Output
Enter elements of array: 3
Enter elements of array: 10
10
10
Sum=30
calloc() function in C
1.#include<stdio.h>
2.#include<stdlib.h>
3.int main(){
4. int n,i,*ptr,sum=0;
5. printf("Enter number of elements: ");
6. scanf("%d",&n);
7. ptr=(int*)calloc(n,sizeof(int)); //memory allocated using call
oc
8. if(ptr==NULL)
9. {
10. printf("Sorry! unable to allocate memory");
11. exit(0);
12. }
13. printf("Enter elements of array: ");
14. for(i=0;i<n;++i)
15. {
16. scanf("%d",ptr+i);
17. sum+=*(ptr+i);
18. }
19. printf("Sum=%d",sum);
20. free(ptr);
21. return 0;
22. }
Output
Enter elements of array: 3
Enter elements of array: 10
10
10
Sum=30
Primitive data structure is a kind of data Non-primitive data structure is a type of data
structure that stores the data of only one structure that can store the data of more than one
type. type.
Examples of primitive data structure are Examples of non-primitive data structure are Array,
integer, character, float. Linked list, stack.
Primitive data structure will contain some Non-primitive data structure can consist of a NULL
value, i.e., it cannot be NULL. value.
The size depends on the type of the data In case of non-primitive data structure, size is not
structure. fixed.
Primitive data structure can be used to call Non-primitive data structure cannot be used to call
the methods. the methods.
Primitive data structure is a data structure that can hold a single value in a specific location
whereas the non-linear data structure can hold multiple values either in a contiguous
location or random locations
The examples of primitive data structure are float, character, integer and pointer. The value
to the primitive data structure is provided by the programmer. The following are the four
primitive data structures:
o Integer: The integer data type contains the numeric values. It contains the whole
numbers that can be either negative or positive. When the range of integer data type
is not large enough then in that case, we can use long.
o Float: The float is a data type that can hold decimal values. When the precision of
decimal value increases then the Double data type is used.
o Boolean: It is a data type that can hold either a True or a False value. It is mainly used
for checking the condition.
o Character: It is a data type that can hold a single character value both uppercase and
lowercase such as 'A' or 'a'.
In case of linear data structure, the data is stored in a sequence, i.e., one data after another
data. When we access the data from the linear data structure, we just need to start from one
place and will find other data in a sequence.
o Array: An array is a data structure that can hold the elements of same type. It cannot
contain the elements of different types like integer with character. The commonly
used operation in an array is insertion, deletion, traversing, searching.
For example:
The above example is an array that contains the integer type elements stored in a
contiguous manner.
In the above example, the length of the string is 17 as the last character is the NULL
character which denotes the termination of the string.
Char Representation:
1. char name[100] = {'H', 'e', 'l','l','o',' ', 'j', 'a', 'v', 'a', 't','p', 'o', 'i', 'n', 't' }
In the above example, the length of the string is 16 as it does not have any NULL character
as the last character to denote the termination.
o Stack: Stack is a data structure that follows the principle LIFO (Last In First Out). All
the operations on the stack are performed from the top of the stack such as PUSH
and POP operation. The push operation is the process of inserting element into the
stack while the pop operation is the process of removing element from the stack. The
stack data structure can be implemented by using either array or linked list.
o Queue: Queue is a data structure that can be implemented by using array. The
difference between the stack and queue data structure is that the elements in the
queue are inserted from the rear end while the elements in the queue are removed
from the front end.
The two things we must know about the data types are:
The two things we must know about the data types are:
Operations that can be performed on the data type are addition, subtraction, multiplication,
bitwise operations, etc.
Operations that can be performed on the data type are addition, subtraction, multiplication,
division, etc. (bitwise and % operations are not allowed).
So, it is cleared from the above examples that data type does not only define a certain
domain of values but also defines operations that can be performed on those values.
In contrast to primitive data types, there is a concept of user-defined data types. The values
and the operations that can be performed on the primitive data types are not specified by
the language itself, but it is specified by the user only. The examples of user-defined data
types are structure, union, and enumeration. By using the structures, we can define our own
type by combining other primitive data types. Let's understand through an example.
1. struct point
2. {
3. int x;
4. int y;
5. }
In the above code, we have created a user-defined data type named 'point' that is made by
combining two primitive data types of integer type named 'x' and 'y'.
Abstract data types are like user-defined data types, which define the operations on the
values using functions without specifying what is inside the function and how the operations
are performed.
For example:
Stack ADT: Here, the stack consists of elements of the same type arranged in sequential
order. The following are the operations that can be performed on the stack are:
Note: We can think of ADT as a black box that hides the user's inner structure and design of the data
type.
There are multiple ways to implement an ADT. For example, a stack ADT can be implemented
using arrays or linked lists.
Why ADT?
The program which uses data structure is known as a client program, and it has access to the
ADT or interface. The program that implements the data structure is known as
implementation.
Advantage
f someone wants to use the stack in the program, he can directly use the push and pop
operations in the program without knowing its implementation details.
What is data structure?
A Data structure is a collection of different types of data on which a specific set of operations
can be performed. It is a collection of different data types. It is a way of organizing the data
in memory. The various operations that can be performed on a data structure are insertion,
deletion, and traversal. For example, if we want to store the data of many students where
each student has a student name, student id, and a mobile number. To store such big data
requires complex data management, which requires a data structure comprising multiple
primitive data types.
A Data type is one of the forms of a variable to A Data structure is a collection of data of different
which the value can be assigned of a given type data types. This collection of data can be
only. This value can be used throughout the represented using an object and can be used
program. throughout the program.
The implementation of data type is known as The implementation of data structure is known as
an abstract implementation. a concrete implementation.
It can hold value but not data. Therefore, we It can hold multiple types of data within a single
can say that it is data-less. object.
In case of data type, a value can be assigned In the case of data structure, some operations are
directly to the variables. used to assign the data to the data structure
object.
`There is no problem in the time complexity. When we deal with a data structure object, time
complexity plays an important role.
The examples of data type are int, float, char. The examples of data structure are stack, queue,
tree, graph.
int main()
{
struct node ob;
return 0;
}
In the above example ‘link’ is a pointer to a structure of type ‘node’. Hence, the
structure ‘node’ is a self-referential structure with ‘link’ as the referencing pointer.
An important point to consider is that the pointer should be initialized properly before
accessing, as by default it contains garbage value.
Types of Self Referential Structures
1. Self Referential Structure with Single Link
2. Self Referential Structure with Multiple Links
Self Referential Structure with Single Link: These structures can have only one
self-pointer as their member. The following example will show us how to connect the
objects of a self-referential structure with the single link and access the corresponding
data members. The connection formed is shown in the following figure.
Implementation:
• C++
• Java
• Python3
• C#
• Javascript
#include <stdio.h>
struct node {
int data1;
char data2;
};
int main()
ob1.link = NULL;
ob1.data1 = 10;
ob1.data2 = 20;
// Initialization
ob2.link = NULL;
ob2.data1 = 30;
ob2.data2 = 40;
ob1.link = &ob2;
printf("%d", ob1.link->data1);
printf("\n%d", ob1.link->data2);
return 0;
30
40
Self Referential Structure with Multiple Links: Self referential structures with
multiple links can have more than one self-pointers. Many complicated data structures
can be easily constructed using these structures. Such structures can easily connect to
more than one nodes at a time. The following example shows one such structure with
more than one links.
The connections made in the above example can be understood using the following
figure.
Implementation:
isPalindrome = true
for i from 0 to s->top:
if pop(&tempStack) != s->arr[i]:
isPalindrome = false
break
if isPalindrome:
Print "The stack is a palindrome."
else:
Print "The stack is not a palindrome."
#include <stdio.h>
#include <stdbool.h>
#define MAX 10
// Stack structure
struct Stack
{
int arr[MAX];
int top;
};
// Function prototypes
void initializeStack(struct Stack *s);
bool isFull(struct Stack *s);
bool isEmpty(struct Stack *s);
void push(struct Stack *s, int element);
int pop(struct Stack *s);
void displayStatus(struct Stack *s);
void checkPalindrome(struct Stack *s);
void menu();
int main()
{
struct Stack stack;
initializeStack(&stack);
do
{
menu();
printf("Enter your choice: ");
scanf("%d", &choice);
switch (choice)
{
case 1:
printf("Enter element to push: ");
scanf("%d", &element);
push(&stack, element);
break;
case 2:
element = pop(&stack);
if (element != INT_MIN)
{
printf("Popped element: %d\n", element);
}
break;
case 3:
checkPalindrome(&stack);
break;
case 4:
displayStatus(&stack);
break;
case 5:
// Exit the program
printf("Exiting program.\n");
return 0;
default:
printf("Invalid choice. Please try again.\n");
}
return 0;
} /* End of Switch */
if (isPalindrome)
{
printf("The stack is a palindrome.\n");
}
else
{
printf("The stack is not a palindrome.\n");
}
} /* End of checkPalindrome() */