0% found this document useful (0 votes)
15 views

DS NotesNLab2

The document discusses different types of data structures including primitive and non-primitive data structures. Primitive data structures store a single value type while non-primitive can store multiple types. Non-primitive are further divided into linear and non-linear categories. Common linear structures include arrays, stacks and queues while common non-linear structures are trees and graphs.

Uploaded by

parshya manolkar
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
15 views

DS NotesNLab2

The document discusses different types of data structures including primitive and non-primitive data structures. Primitive data structures store a single value type while non-primitive can store multiple types. Non-primitive are further divided into linear and non-linear categories. Common linear structures include arrays, stacks and queues while common non-linear structures are trees and graphs.

Uploaded by

parshya manolkar
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 62

Data Structures

Data structure is the structural representation of logical

relationships between elements of data. In other words a

data structure is a way of organizing data items by

relationship to each other.

Data structure mainly specifies the structured organization of

data, by providing accessing methods with correct degree of

associativity. Data structure affects the design of both the

structural and functional aspects of a program.

Algorithm + Data Structure = Program

Data structures are the building blocks of a program; here

the selection of a particular data structure will help the

programmer to design more efficient programs as the complexity

and volume of the problems solved by the computer is steadily

increasing day by day. The programmers have to strive hard to solve

these problems. If the problem is analyzed and divided into sub

problems, the task will be much easier i.e., divide, conquer and
combine. A complex problem usually cannot be divided and

programmed by set of modules unless its solution is structured or

organized. This is because when we divide the big problems into sub

problems, these sub problems will be programmed by different

programmers or group of programmers. But all the programmers

should follow a standard structural method so as to make easy and

efficient integration of these modules. Such type of hierarchical

structuring of program modules and sub modules should not only

reduce the complexity and control the flow of program statements

but also promote the proper structuring of information. By choosing

a particular structure (or data structure) for the data items, certain

data items become friends while others loses its relations.

Primitive vs non-primitive data structure


Data structure means organizing the data in the
memory. The data can be organized in two ways either
linear or non-linear way.

There are two types of data structure available for the


programming purpose:

o Primitive data structure


o Non-primitive data structure

Primitive data structure is a fundamental type of data


structure that stores the data of only one type whereas
the non-primitive data structure is a type of data
structure which is a user-defined that stores the data of
different types in a single entity.

In the above image, we can observe the classification of


the data structure. The data structure is classified into
two types, i.e., primitive and non-primitive data
structure. In the case of primitive data structure, it
contains fundamental data types such as integer, float,
character, pointer, and these fundamental data types can
hold a single type of value. For example, integer variable
can hold integer type of value, float variable can hold
floating type of value, character variable can hold
character type of value whereas the pointer variable can
hold pointer type of value.
In the case of non-primitive data structure, it is categorized into two parts such as
linear data structure and non-linear data structure. Linear data structure is a
sequential type of data structure, and here sequential means that all the elements
in the memory are stored in a sequential manner; for example, element stored
after the second element would be the third element, the element stored after
the third element would be the fourth element and so on. We have different
linear data structures holding the sequential values such as Array, Linked
list, Stack, Queue.

Non-linear data structure is a kind of random type of data structure. The non-
linear data structures are Tree and Graph.

Let's understand the differences between the primitive and non-primitive


data structure.

Primitive data structure Non-primitive data structure

Primitive data structure is a kind of Non-primitive data structure is a type of


data structure that stores the data data structure that can store the data of
of only one type. more than one type.

Examples of primitive data structure Examples of non-primitive data structure


are integer, character, float. are Array, Linked list, stack.

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.

It starts with a lowercase character. It starts with an uppercase character.

Primitive data structure can be used Non-primitive data structure cannot be


to call the methods. used to call the methods.

Primitive data structure

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'.

Non-primitive data structure


The non-primitive data structure is a kind of data structure that can hold multiple
values either in a contiguous or random location. The non-primitive data types
are defined by the programmer. The non-primitive data structure is further
classified into two categories, i.e., linear and non-linear data structure.

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.

The following are the types of linear data structure:

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:

int a[6] = {1,2,3,4,5,6};

The above example is an array that contains the integer type elements stored in a
contiguous manner.

o String: String is defined as an array of characters. The difference between


the character array and string is that the string data structure terminates
with a 'NULL' character, and it is denoted as a '\0'.

String data structure:

1. char name[100] = "Hello javaTpoint";

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?

What is a Memory Address in C?

Whenever a variable is defined in C language, a memory location is


assigned for it, in which it's value gets stored. We can check this memory
address, using the & symbol.

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;

printf("Value of the variable var is: %d\n", var);

printf("Memory address of the variable var is:


%x\n", &var);

Value of the variable var is: 7

Memory address of the variable var is: bcc7a00

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?

Like we mentioned earlier, a Pointer in C language is a variable that holds a


memory address.

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.

Whenever a variable is declared in a program, system


allocates a location i.e an address to that variable in the
memory, to hold the assigned value. This location has its
own address number, which we saw in the program
above.

Let us assume that system has allocated memory


location 80F for a variable a.
int a = 10;

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.

So if you have to define a pointer variable, the syntax is a little different.

Following is the syntax for declaring a variable as a pointer:

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.

The data type of the pointer variable should be the same as of


the variable to which the pointer is pointing.
Pointer Operators in C

There are two pointer operators in C, they are:

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

In the variable a, the memory address of the variable b will get


stored.

The * operators is the complement of &. This operator returns


the value located at the given address.

For example, if a contains the memory address of the variable b,


then the code,

c = *a;

Copy

will store the value of the variable b into c.

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;

// assign value to pointer

ptr = &x;

printf("Value at ptr is: %d \n", *ptr);

printf("Address pointed by ptr is: %p \n", ptr);

return 0;

Copy

Value at ptr is: 99


Address pointed by ptr is: 0x7fff99c0e6c4
Run Code →

The %p format specifier is used for pointer variable.

Benefits of using pointers in C

Below we have listed a few benefits of using pointers:


1. Pointers are more efficient in handling Arrays in
C and Structures in C.
2. Pointers allow references to function and thereby help in
passing of function as arguments to other functions.
3. Pointers also provide means by which a function in C can
change its calling arguments.
4. It reduces length of the program and its execution time as
well.
5. It allows C language to support Dynamic Memory
management.
In the next tutorial we will learn syntax of pointers, how to
declare and define a pointer, and using a pointer. See you in
the next tutorial.

A pointer is a variable used to store memory address. Hence,


we have to declare and initialize (assign it a value) it just like
any other variable. Pointers can be very useful in some use-
cases, like:

• They make accessing array elements easier.


• We can implement linked lists, trees, and graphs using
pointers.
• We use pointers for accessing dynamically allocated
memory.
• We can return more than one value from a function using
pointers.
So let's see how we can create pointers, assign values to
pointers, perform pointer conversions, pointer arithmetic and
pointer comparisons.
Declaring a Pointer in C

The general syntax of pointer declaration is,

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.

Following are some examples of declaring a pointer in C:

int *ptr; //pointer to int

float *ptr; //pointer to float

char *ptr; //pointer to char

double *ptr; //pointer to double

Copy

Just like a variable, pointer is declared in the same way, just with an
additional pointer operator *.

Assigning Value to a Pointer Variable

When we declare a pointer, it contains garbage value, which


means it could be pointing anywhere in the memory. Pointer
Initialization is the process of assigning the address of a
variable to a pointer. In C language, the address operator & is
used to determine the address of a variable.
The & (immediately preceding a variable name) returns the
address of the variable associated with it.
For example,

#include<stdio.h>

int main(void)

int a = 10;

// declare a pointer

int *ptr;

// assign value to pointer

ptr = &a;

printf("Value at ptr is: %d \n", *ptr);

printf("Address pointed by ptr is: %p \n", ptr);

return 0;

Copy

Value at ptr is: 10


Address pointed by ptr is: 0x7fff99c0e6c4
Run Code →
Pointer variables must always point to variables of the same datatype.

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;

// assign value to pointer

ptr = &a;

printf("Value at ptr is: %d \n", *ptr);


printf("Address pointed by ptr is: %p \n", ptr);

return 0;

Copy

warning: assignment from incompatible pointer type


ptr = &x;
Run Code →

While declaring a pointer variable, if it is not assigned to anything then it


contains garbage value. And that can lead to unexpected errors in your
program. Hence, it is recommended to assign a NULL value to it.

When we assign NULL to a pointer, it means that it does not point to any
valid address. NULL denotes the value 'zero'.

A pointer that is assigned a NULL value is called a NULL pointer in C.

We can give a pointer a null value by assigning it zero to it. For


example,

int *ptr = 0;
Copy

The above code will initialize the ptr pointer will a null value.

We can also use the NULL macro, which is nothing but a


predefined constant for null pointer. This is defined in
the <stdio.h> header library.

int *ptr = NULL;

Pointer to Pointer Assignment in C

We can use an assignment operator to assign value of a pointer


to another pointer variable. But for such assignment, types of
both the pointer should be same.

Let's take a code example,

#include<stdio.h>

int main(void)

float a = 10;

// declare two pointers

int *p1, *p2;

// assign value to pointer

p1 = &a;

// assign value from one pointer to another

p2 = p1;

printf("Value at p1 and p2: %d %d \n", *p1, *p2);


printf("Address pointed by p1 and p2: %p %p \n",
p1, p2);

return 0;

Value at p1 and p2: 10 10


Address pointed by p1 and p2: 0x7fff99c0e6c4
0x7fff99c0e6c4
As you can see in the code example above, multiple pointers
can point to the same variable but they should be of the same
data type.

Pointer Type Conversion in C

We can assign a pointer of one type to a pointer of another


type by doing pointer type conversion.

1. void * pointer

The pointers of type void * are known as Generic pointers, and


they can be assigned to any other type of pointer. Also, any
other type of pointer can be assigned to a void * pointer. The
void pointers refer to the pointers that have no data type
associated with them. As the name suggests, the void pointer
indicates that the pointer is basically empty- and thus, it is
capable of holding any data type address in the program.
2. Pointer type conversion

For pointer type other than void *, we have to explicitly cast


pointer from one type to another. But this can lead to
unexpected behavior for incompatible data types.

For example, if we have a variable of type double, and we want


to use a pointer of type int to point to this variable. Even after
using explicit cast, the pointer will work as if it is pointing to
a int type value. Now, a double type is of 8 bytes whereas
an int type is of 4 bytes, hence, 4 bytes of information will be
lost.

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;

// assign value to pointer with casting

p1 = (int *) &a;

// value of 'b' should be same as 'a', but it won't


be

b = *p1;
printf("Value of a is: %f \n", b);

return 0;

Copy

Value of a is: -858993459.000000

Pointer and Arrays

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.

For example, if we have,

int a = 5;

int *ptr1 = &a;

float b = 5.5;

float *ptr2 = &b;

// *ptr1 = 2 is equivalent to a = 2

// (*ptr1)++ is equivalent to a++

// float z = *ptr2 + 4.2 is equivalent to float z = b +


4.2;
Here is one complete program,

#include <stdio.h>

int main()

int a;

a = 10;

int *p = &a; // declaring and initializing the


pointer

//prints the value of 'a'

printf("%d\n", *p);

printf("%d\n", *&a);

//prints the address of 'a'

printf("%u\n", &a);

printf("%u\n", p);

printf("%u\n", &p); //prints address of 'p'

return 0;

10
10
3795480300
3795480300
3795480304
Points to Remember while using Pointers

• A pointer variable stores the address of a variable. We use * to


declare and identify a pointer.
• We can find the address of any variable using the & (ampersand)
operator.
• The declaration int *a doesn't mean that a is going to contain an
integer value. It means that a is going to contain the address of a
variable of int type.
• We can dereference a pointer variable using a * operator. Here,
the * can be read as 'value at'.

Simple program to represent Pointer to a Pointer

#include <stdio.h>

int **p1;

#include <stdio.h>

int main() {

int a = 10;

int *p1; //this can store the address of variable a

int **p2;

/*

this can store the address of pointer variable p1 only.

It cannot store the address of variable 'a'

*/

p1 = &a;

p2 = &p1;
printf("Address of a = %u\n", &a);

printf("Address of p1 = %u\n", &p1);

printf("Address of p2 = %u\n\n", &p2);

// below print statement will give the address of 'a'

printf("Value at the address stored by p2 = %u\n", *p2);

printf("Value at the address stored by p1 = %d\n\n", *p1);

printf("Value of **p2 = %d\n", **p2); //read this *(*p2)

/*

This is not allowed, it will give a compile time error-

p2 = &a;

printf("%u", p2);

*/

return 0;

Address of a = 2686724
Address of p1 = 2686728
Address of p2 = 2686732

Value at the address stored by p2 = 2686724


Value at the address stored by p1 = 10

Value of **p2 = 10

Explanation of the above program


• p1 pointer variable can only hold the address of the variable a (i.e
Number of indirection operator(*)-1 variable). Similarly, p2 variable
can only hold the address of variable p1. It cannot hold the address of
variable a.

• *p2 gives us the value at an address stored by the p2 pointer. p2 stores


the address of p1 pointer and value at the address of p1 is the address
of variable a. Thus, *p2 prints address of a.

• **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.

Pointer and Arrays in C


Array in C

When an array in C language is declared, compiler allocates sufficient


memory to contain all its elements. Its base address is also allocated by the
compiler.

Declare an array arr,

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 -

• It is the name of the array


• It acts as a pointer pointing towards the first element in the array.

arr is equal to &arr[0] by default


For better understanding of the declaration and initialization of the pointer
- click here. and refer to the program for its implementation.

NOTE:

• You cannot decrement a pointer once incremented. p-- won't work.

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 a[3] = {1, 2, 3};

int *p = a;

for (int i = 0; i < 3; i++)

printf("%d", *p);

p++;

return 0;

}
Copy

1 2 3

Syntax:

*(a+i) //pointer with an array

Copy

is same as:

a[i]
Pointer to Multidimensional Array

Let's see how to make a pointer point to a multidimensional array.


In a[i][j], a will give the base address of this array, even a + 0 + 0 will also give
the base address, that is the address of a[0][0] element.

Syntax:

*(*(a + i) + j)

Copy

Pointer and Character strings

Pointer is used to create strings. Pointer variables of char type are treated as
string.

char *str = "Hello";

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".

• The string created using char pointer can be assigned a value


at runtime.

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.

Pointer to Array of Structures in C


Like we have array of integers, array of pointers etc, we can also have array
of structure variables. And to use the array of structure variables efficiently,
we use pointers of structure type. We can also have pointer to a single
structure variable, but it is mostly used when we are dealing with array of
structure variables.

#include <stdio.h>

struct Book

char name[10];

int price;
}

int main()

struct Book a; //Single structure variable

struct Book* ptr; //Pointer of Structure type

ptr = &a;

struct Book b[10]; //Array of structure variables

struct Book* p; //Pointer of Structure type

p = &b;

return 0;

}
Accessing Structure Members with Pointer

To access members of structure using the structure variable, we used the


dot . operator. But when we have a pointer of structure type, we use arrow -
> to access structure members.

#include <stdio.h>

struct my_structure {

char name[20];

int number;

int rank;

};

int main()

struct my_structure variable = {"StudyTonight", 35,


1};
struct my_structure *ptr;

ptr = &variable;

printf("NAME: %s\n", ptr->name);

printf("NUMBER: %d\n", ptr->number);

printf("RANK: %d", ptr->rank);

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.

Size of datatypes on 16-bit Machine:

Type Size (in bytes)


int or signed int 2

char 1

long 4

float 4

double 8

long double 10

Examples for Pointer Arithmetic

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.

32 bit Machine (Visual Basic C++)

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.

And, following is a table for Size of datatypes on 32-bit Machine :

Type Size (in bytes)

int or signed int 4

char 2

long 8

float 8
double 16

Note: We cannot add two pointers. This is because pointers contain


addresses, adding two addresses makes no sense, because you have no
idea what it would point to.

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.

Program for pointer arithmetic(32-bit machine)

#include <stdio.h>

int main()

int m = 5, n = 10, o = 0;

int *p1;

int *p2;

int *p3;

p1 = &m; //printing the address of m

p2 = &n; //printing the address of n


printf("p1 = %d\n", p1);

printf("p2 = %d\n", p2);

o = *p1+*p2;

printf("*p1+*p2 = %d\n", o);//point 1

p3 = p1-p2;

printf("p1 - p2 = %d\n", p3); //point 2

p1++;

printf("p1++ = %d\n", p1); //point 3

p2--;

printf("p2-- = %d\n", p2); //point 4

//Below line will give ERROR

printf("p1+p2 = %d\n", p1+p2); //point 5

return 0;

Copy
p1 = 2680016

p2 = 2680012

*p1+*p2 = 15

p1-p2 = 1

p1++ = 2680020

p2-- = 2680008

Explanation of the above program:

1. Point 1: Here, * means 'value at the given address'. Thus, it adds the
value of m and n which is 15.

2. Point 2: It subtracts the addresses of the two variables and then


divides it by the size of the pointer datatype (here integer, which has
size of 4 bytes) which gives us the number of elements of integer
data type that can be stored within it.

3. Point 3: It increments the address stored by the pointer by the size of


its datatype(here 4).

4. Point 4: It decrements the address stored by the pointer by the size


of its datatype(here 4).

5. Point 5: Addition of two pointers is not allowed.

Pointers as Function Argument in C


Pointer as a function parameter is used to hold addresses of arguments
passed during function call. This is also known as call by reference. When a
function is called by reference any change made to the reference variable
will effect the original variable.

Example Time: Swapping two numbers using Pointer


#include <stdio.h>

void swap(int *a, int *b);

int main()

int m = 10, n = 20;

printf("m = %d\n", m);

printf("n = %d\n\n", n);

swap(&m, &n); //passing address of m and n to


the swap function

printf("After Swapping:\n\n");

printf("m = %d\n", m);

printf("n = %d", n);

return 0;

/*

pointer 'a' and 'b' holds and

points to the address of 'm' and 'n'

*/

void swap(int *a, int *b)

int temp;

temp = *a;
*a = *b;

*b = temp;

Copy

m = 10

n = 20tt

After Swapping:

m = 20

n = 10

Functions returning Pointer variables

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>

int* larger(int*, int*);

void main()

int a = 15;

int b = 92;

int *p;
p = larger(&a, &b);

printf("%d is larger",*p);

int* larger(int *x, int *y)

if(*x > *y)

return x;

else

return y;

92 is larger

Safe ways to return a valid Pointer.

1. Either use argument with functions. Because argument passed to


the functions are declared inside the calling function, hence they will
live outside the function as well.

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

It is possible to declare a pointer pointing to a function which can then be


used as an argument in another function. A pointer to a function is declared
as follows,

type (*pointer-name)(parameter);

Copy

Here is an example :

int (*sum)(); //legal declaration of pointer to


function

int *sum(); //This is not a declaration of pointer


to function

Copy

A function pointer can point to a specific function when it is assigned the


name of that function.

int sum(int, int);

int (*s)(int, int);

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);

Example of Pointer to Function


#include <stdio.h>

int sum(int x, int y)

return x+y;

int main( )

int (*fp)(int, int);

fp = sum;

int s = fp(10, 15);

printf("Sum is %d", s);

return 0;

25

Complicated Function Pointer example

void *(*foo) (int*);

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

The concept of dynamic memory allocation in c


language enables the C programmer to allocate memory at
runtime. Dynamic memory allocation in c language is possible
by 4 functions of stdlib.h header file.

1. malloc()
2. calloc()
3. realloc()
4. free()

Before learning above functions, let's understand the difference


between static memory allocation and dynamic memory
allocation.

static memory allocation dynamic memory allocation

memory is allocated at compile memory is allocated at run time.


time.

memory can't be increased while memory can be increased while


executing program. executing program.

used in array. used in linked list.

Now let's have a quick look at the methods used for dynamic
memory allocation.

malloc() allocates single block of requested memory.


calloc() allocates multiple block of requested memory.

realloc() reallocates the memory occupied by malloc() or calloc()


functions.

free() frees the dynamically allocated memory.

malloc() function in C

The malloc() function allocates single block of requested


memory.

It doesn't initialize memory at execution time, so it has garbage


value initially.

It returns NULL if memory is not sufficient.

The syntax of malloc() function is given below:

1. ptr=(cast-type*)malloc(byte-size)

Let's see the example of malloc() function.

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

The calloc() function allocates multiple block of requested


memory.

It initially initialize all bytes to zero.

It returns NULL if memory is not sufficient.

The syntax of calloc() function is given below:


1. ptr=(cast-type*)calloc(number, byte-size)

Let's see the example of calloc() function.

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 Non-primitive data structure

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.

It starts with a lowercase character. It starts with an uppercase character.

Primitive data structure can be used to call Non-primitive data structure cannot be used to call
the methods. the methods.

Primitive data structure

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'.

Non-primitive data structure


The non-primitive data structure is a kind of data structure that can hold multiple values
either in a contiguous or random location. The non-primitive data types are defined by the
programmer. The non-primitive data structure is further classified into two categories, i.e.,
linear and non-linear data structure.

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.

The following are the types of linear data structure:

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:

int a[6] = {1,2,3,4,5,6};

The above example is an array that contains the integer type elements stored in a
contiguous manner.

o String: String is defined as an array of characters. The difference between the


character array and string is that the string data structure terminates with a 'NULL'
character, and it is denoted as a '\0'.

String data structure:

1. char name[100] = "Hello javaTpoint";

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.

Data types vs data structure


What is a data type?

The two things we must know about the data types are:

Data types vs data structure


What is a data type?

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.

If the data is of float (floating) type

Then it takes only floating type values.

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.

User-defined data type

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

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:

o initialize(): This method initializes the stack to be empty.


o push(): It is a method used for inserting an element into the stack.
o pop(): It is a method used for removing the element from the stack.
o isEmpty(): This method is used to check whether the stack is empty or not.
o isfull(): It checks whether the stack is full or not.

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.

Differences between the data type and the data structure


Data type Data structure

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.

Self Referential Structures


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

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

struct node* link;

};

int main()

struct node ob1; // Node1


// Initialization

ob1.link = NULL;

ob1.data1 = 10;

ob1.data2 = 20;

struct node ob2; // Node2

// Initialization

ob2.link = NULL;

ob2.data1 = 30;

ob2.data2 = 40;

// Linking ob1 and ob2

ob1.link = &ob2;

// Accessing data members of ob2 using ob1

printf("%d", ob1.link->data1);

printf("\n%d", ob1.link->data2);

return 0;

Learn Data Structures & Algorithms with GeeksforGeeks


Output

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:

Applications: Self-referential structures are very useful in creation of other complex


data structures like:
• Linked Lists
• Stacks
• Queues
• Trees
• Graphs etc.
/* Lab Assignment-2*/
Problem Definition: A menu driven STACK implentation program in
C that uses functions to accept stack of integers with maximum size
MAX. The functions of Stack should include to:
1. Push an element onto stack
2. Pop an element from stack
3. Demonstrate the operation for checking Palindrome
4. Demonstrate to check overflow and underflow situations in stack
5. Display the status of stack
6. Exit

Algorithm: Menu-Driven Stack Implementation in C


Step 1: Define the Stack structure
struct Stack
{
int arr[MAX];
int top;
}

Step 2: Function to initialize the stack


initializeStack(struct Stack *s):
s->top = -1;

Step 3: Function to check if the stack is full


isFull(struct Stack *s):
return s->top == MAX - 1;

Step 4: Function to check if the stack is empty


isEmpty(struct Stack *s):
return s->top == -1;

Step 5: Function to push an element onto the stack


push(struct Stack *s, int element):
if isFull(s):
Print "Stack overflow! Cannot push element."
else:
s->top++
s->arr[s->top] = element
Print "Element element pushed onto the stack."

Step 6: Function to pop an element from the stack


pop(struct Stack *s) -> int:
if isEmpty(s):
Print "Stack underflow! Cannot pop element."
return INT_MIN
else:
poppedElement = s->arr[s->top]
s->top--
return poppedElement

Step 7: Function to display the status of the stack


displayStatus(struct Stack *s):
if isEmpty(s):
Print "Stack is empty."
else:
Print "Stack elements:"
for i from 0 to s->top:
Print s->arr[i]

Step 8: Function to check if the stack is a palindrome


checkPalindrome(struct Stack *s):
tempStack = create an empty stack
for i from 0 to s->top:
push(&tempStack, s->arr[i])

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."

Step 9: Function to display the menu


menu():
Print "\nMenu:"
Print "1. Push an element onto stack"
Print "2. Pop an element from stack"
Print "3. Check for Palindrome"
Print "4. Display stack status"
Print "5. Exit"

Step 10: Main function


main():
Initialize the stack
Loop until the user chooses to exit:
Call menu() to display options
Read user's choice
Switch on the choice:
Case 1: Read element, call push()
Case 2: Call pop() and print popped element
Case 3: Call checkPalindrome()
Case 4: Call displayStatus()
Case 5: Exit the loop
Default: Print "Invalid choice. Please try again."
/* C PROGRAM*/

#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);

int choice, element;

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");
}

} while (choice != 6);

return 0;
} /* End of Switch */

// Function to initialize the stack


void initializeStack(struct Stack *s)
{
s->top = -1;
}

// Function to check if the stack is full


bool isFull(struct Stack *s)
{
return s->top == MAX - 1;
}

// Function to check if the stack is empty


bool isEmpty(struct Stack *s)
{
return s->top == -1;
}

// Function to push an element onto the stack


void push(struct Stack *s, int element) {
if (isFull(s))
{
printf("Stack overflow! Cannot push element.\n");
}
else
{
s->arr[++s->top] = element;
printf("Element %d pushed onto the stack.\n", element);
}
}

// Function to pop an element from the stack


int pop(struct Stack *s)
{
if (isEmpty(s))
{
printf("Stack underflow! Cannot pop element.\n");
return INT_MIN;
}
else
{
return s->arr[s->top--];
}
} /* End of pop()*/

// Function to display the status of the stack


void displayStatus(struct Stack *s)
{
if (isEmpty(s))
{
printf("Stack is empty.\n");
}
else
{
printf("Stack elements: ");
for (int i = 0; i <= s->top; ++i) {
printf("%d ", s->arr[i]);
}
printf("\n");
}
} /* End of DisplayStatus() */

// Function to check if the stack is a palindrome


void checkPalindrome(struct Stack *s)
{
struct Stack tempStack;
initializeStack(&tempStack);

// Copy elements to a temporary stack


for (int i = 0; i <= s->top; ++i)
{
push(&tempStack, s->arr[i]);
}

// Compare original stack with the temporary stack


bool isPalindrome = true;
for (int i = 0; i <= s->top; ++i)
{
if (pop(&tempStack) != s->arr[i])
{
isPalindrome = false;
break;
}
} /* End of for loop */

if (isPalindrome)
{
printf("The stack is a palindrome.\n");
}
else
{
printf("The stack is not a palindrome.\n");
}
} /* End of checkPalindrome() */

// Function to display the menu


void menu(
{
printf("\nMenu:\n");
printf("1. Push an element onto stack\n");
printf("2. Pop an element from stack\n");
printf("3. Check for Palindrome\n");
printf("4. Display stack status\n");
printf("5. Exit\n");
}

You might also like