0% found this document useful (0 votes)
49 views137 pages

DSA - CP Revision

The document discusses the C programming language and how programs are executed by the operating system. It explains that when a C program is compiled, it generates an executable file that is saved to disk. When the program is run, the operating system loads the executable into memory and executes it line by line on the CPU. It also describes where variables are stored in memory, the data types in C, and how values are represented in memory.

Uploaded by

f20212653
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)
49 views137 pages

DSA - CP Revision

The document discusses the C programming language and how programs are executed by the operating system. It explains that when a C program is compiled, it generates an executable file that is saved to disk. When the program is run, the operating system loads the executable into memory and executes it line by line on the CPU. It also describes where variables are stored in memory, the data types in C, and how values are represented in memory.

Uploaded by

f20212653
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/ 137

Revision of Programming

Fundamentals - DSA
BITS Pilani Jagat Sesh Challa
Pilani Campus
BITS Pilani
Pilani Campus

The C Programming Language


The C language
• General Purpose high-level programming language

• Language is platform independent

• Closely associated with the UNIX operating system

• Most versatile as it supports direct access of memory


locations through pointers

• Compiler based language

• C programs are fastest in execution time!

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
BITS Pilani
Pilani Campus

Program and Process Execution


What happens to your program?

You write a program…

1. Where is your program saved?

2. What happens to your program when you try to compile and run it?

Before we answer the above questions let us see what is an


operating system…

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Operating System (OS)
• An OS is a layer of software interposed between the
application program and the hardware

• OS manages everything of your computer including hardware


• OS is responsible for executing your program
• A program under execution is known as a process

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Basic layout of Computer Hardware

OS
Manages
these
resources

CPU Disk

Memory (RAM)
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
What happens to your program?

Now let us answer these questions…

1. Where is your program saved?

2. What happens to your program when you try to compile and run it?

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
1. Where is your program saved?

Your program
when saved gets
stored on the
disk

Program

CPU DISK

Memory (RAM)
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
What happens to your program?

Now let us answer these questions…

1. Where is your program saved?

2. What happens to your program when you try to compile and run it?

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
2. What happens to your program
when you try to compile and run it?
• OS loads the
program executable
into the RAM
• Executes it line by
line on CPU

A line Program Executable Program


from exe (exe) (P1)
Program is Compiled
executed Executable
Program of P1 (exe)
on CPU
CPU Executable gets
line by line
loaded into the
RAM

Memory (RAM) DISK


Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Compiling C Program
Say, our C program is stored in myfirst.c
To generate executable file, navigate to the directory where
myfirst.c is stored and run the following command:
gcc myfirst.c
Files generated:
a.out

The above process is known as compilation of the program to


generate the executable a.out. To run the executable:
./a.out

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
The compilation process
The Preprocessor
• lines beginning with # (preprocessor directives)
• #include… or #define PI 3.142
• Source code expanded, comments removed
The Compiler
• Checks the source code for errors
• Creates object code (not ready to run) (why?)
The Linker
• Acts on unresolved references left by compiler
• printf, scanf… their machine code is added
• This code is ready to run
The Assembler (optional)
• Some compilers first translate to assembly language.
• The assembler converts it to machine code
Source of image: https://www.javatpoint.com/flow-of-c-program Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Variables in Main Memory
• Consider the following C Program:
#include <stdio.h>
int main()
{
int num1, num2, num3;
num1 = 2;
num2 = 4;
num3 = num1 + num2; // computing the sum of num1 and num2
printf(“The sum is: %d \n”, num3); // printing the sum
return 0;
}
• This program has three variables: num1, num2 and num3.
• Where are these variables stored?

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Look at the main memory only
• When we compile and execute
a program, OS allocates some
space in the main memory
• The declared variables are
stored in that allocated space.
Space • In our example, num1, num2
allocated num3 Space and num3 are stored in this
num2 allocated to space.
to the
num1
entire main() function • More specifically in the space
program allocated to the main()
function, within the above
space.
o We will study about
memory allocation and
functions in greater detail
later!
Memory (RAM)
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Fundamental data types in C
• Integer (short, int, long, long long)

• Floating point (float, double, long double)

• Character (char)

• Fixed size of each data type / sub-type.

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Machine Readable size of
variables
• Every variable occupies space in the program allocated space
of the main memory
• How much space does each variable occupy?
• It depends on its type!
• For example, variable of type int occupies either 2 or 4 bytes
depending upon the specific compiler you are using.
• What is this byte?
• Before we answer this question, let us see how main memory is
organized!

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Organization of Main Memory

• Main memory is typically a table of


memory locations of 8 bits (0/1) each
• A set of contiguous 8 bits is known as
a byte
• So, each location in this main memory
is of one byte
• We call byte-addressable memory 1 byte

• Each location is associated with an


address.

Each location
is of 8 bits
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Storing int in main memory
• Remember how integer values
are represented in 2’s
complement representation.
• Our machines use 2’s
complement representation to
store integer variables.
• If int variables are of 2 bytes Space occupied
size (or 16 bits), then each int by int variable,
which is 2 bytes or
variable shall occupies 2 16 bits
contiguous locations in the
memory

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Explicit Type Conversion
(Typecasting)
Example1:
Conversion of integer to a float variable
int a = 10;
float f = (float) a;

Example2:
Conversion of integer to a char variable
int a = 20;
char ch = (char) a;

Note: The above conversion is valid as after all characters are


integer values of ASCII codes.

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Functions
Functions are /* myProg.c */ Function
• Declared #include <stdio.h> Declaration
int sum(int a, int b);
• Defined int sum(int a, int b)
• Called {
int total; Function
total = a + b; Definition
return total;
}
int main()
{
int x,y,z;
Function Call
x = 5, y = 4;
z = sum(x,y);
printf(“Sum is %d:”,z};
}
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Function Definitions and
Declarations
• Typically, functions are declared first in the program
• Then the functions are defined.
• Although declaring functions is optional, it recommended to
declare them before defining them
• Helps in writing modular programs
• Typically, functions are declared in “.h” files
• “.h” files are header files
• These “.h” files are included in your “.c” files

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Looking at the main memory
only
/* myProg.c */
#include <stdio.h>
int sum(int a, int b);
int sum(int a, int b)
{
Space int total;
a Space total = a + b;
allocated b allocated to return total;
to the total
“sum()” function }
entire
program x Space allocated int main()
y to “main()” {
z
function int x,y,z;
x = 5, y = 4;
z = sum(x,y);
printf(“Sum:%d”,z};
}
Memory (RAM)
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Swap two numbers and
“Call by Value”
int main()
void swap(int a, int b)
{
{
int x, y;
int c = a;
printf(“Enter the numbers:\n”);
a = b;
scanf(“%d %d”, &x, &y);
b = c;
swap(x, y);
printf(“a=%d, b=%d\n”, a,b);
printf(“x=%d, y=%d\n”,x,y);
return;
return 0;
}
}
Call by value:
Program Execution:
• When a function is being called, the values of the parameters from Enter the numbers:
caller function are copied into the parameters of the called function. 4 5
• Values of x and y are copied into a and b respectively a=5, b=4
• Any change to the values of a and b is not reflected into x and y x=4, y=5
• a and b are swapped in the swap() function. This swap is not
reflected in x and y
• print statement in swap() function prints the swapped values of a & b
• print statement in main() function prints the old values of x and y
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Looking at the main memory
only

Note: we
have flipped
Space our memory
allocated layout
to the our
program

Deeper view of space allocated to our program


Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Functions, local and global
variables in main memory
Stack #include <stdio.h>
int a = 0;
memory allocated void f1(){
to main() in stack printf(“a = %d\n”,a);
int a = 2;
memory allocated printf(“a = %d\n”, a);
to f1() in stack }
void main() {
f1(a);
int a = 5;
printf("a = %d",a);
Heap }
uninitialized data segment

global variable a in
initialized data segment
text segment

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Functions, local and global
variables in main memory
Stack value of local #include <stdio.h>
variable a of main in int a = 0;
stack segment void f1(){
5
printf(“a = %d\n”,a);
int a = 2;
printf(“a = %d\n”, a);
2
}
value of local void main() {
variable a of f1 in f1(a);
stack segment int a = 5;
printf("a = %d",a);
Heap }
uninitialized data segment

2 value of the global variable


a in initialized data segment
text segment

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
How is an array stored in main
memory?
Consider this program:
Addresses
int main(){
10010000 int arr[4] = {1, 2, 3, 4};
10010001

10010010
10010011 return 0;}
10010100
10010101

• Say each integer variable takes 2


bytes of memory
• To store an integer array of size 4,
we need 4*2 = 8 bytes of memory
10011101
or 8 contiguous locations in memory
10011110 (given each location is of size 1 byte)

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
How is an array stored in main
memory?
int arr[4] = {1, 2, 3, 4}; Addresses
10010000
10010001
Stores first element of arr, accessed by arr[0] 10010010
10010011
Stores second element of arr, accessed by arr[1] 10010100
10010101
Stores third element of arr, accessed by arr[2]

Stores fourth element of arr, accessed by arr[3]

10011101
10011110

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
How is an array stored in main
memory?
Addresses
10010000
10010001
10010010 arr points here and contains this address
arr[0] = 1
10010011
10010100 arr+1 refers to this address
arr[1] = 2
10010101
arr+2 refers to this address
arr[2] = 3
arr+3 refers to this address
arr[3] = 4
• We are storing 2 bytes of memory at address arr
• We are storing 2 bytes of memory at address
arr+1, and so on.
• arr and arr+1 differ by one unit of space required
10011101
to store an integer, which is of 2 bytes or 2
10011110
addressable memory locations.
• If our array is storing float values, arr and arr+1
would differ by 4 bytes or 4 addressable memory
locations.
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Can we ‘return’ an array from a
function?
If the array is defined inside the function, returning the array
would give run-time error.
• Why?
• Try this! Next Slide.

We can return dynamically allocated arrays.


• We will study about them when we study pointers.

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Let us try to explain with our
memory diagram
Stack When f1() returns, the
arr
memory allocated memory allocated to it is
1 2 3 4 destroyed.
to f1() in stack
So arr declared inside
memory allocated f1() does not exist
to main() in stack anymore. Accessing arr
in main function now
gives a run-time error.
Consider this program:
int f1(){
Heap int arr[4] = {1, 2, 3, 4};
return arr;}
uninitialized data segment
int main(){
int main_arr[] = f1();
printf(”First ele is: %d”, main_arr[0]);
return 0;}
text segment
Output:
Memory allocated to our program seg fault
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Accessing a 2-D array
int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
for(i=0;i<3;i++)
{
for(j=0;j<4;j++)
{
printf(“%d”,a[i][j]);
}
printf(“\n”);
}
Run time initialization of an array can be
done in similar way by changing printf()
to scanf()inside j loop.

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
sizeof() for struct variables
struct test_struct {
short a; //2bytes printf("a= %lu\n", sizeof(test.a)); = 2
int b; //4bytes printf("b= %lu\n", sizeof(test.b)); = 4
char c; //1byte printf("c= %lu\n", sizeof(test.c)); = 1
} test; printf("%lu\n", sizeof(test)); = 12

• We can notice that the sizeof(test) > sizeof(test.a) +


sizeof(test.b) + sizeof(test.c)
• This is because the compiler adds (may add) padding for alignment requirements
• Padding means to append empty locations towards the end (or beginning)
1000 1001 1002 1003
a (1000, 1001) padding 12 contiguous
b (1004, 5, 6, 7) locations in
main memory
C (1008) padding

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Memory view of storing a
struct variable
struct test_struct { Address
short a; //2bytes
int b; //4bytes a (2 bytes) 1000
char c; //1byte 1001
padding (2 bytes) 1002
} test;
1003
1004
b (4 bytes) 1005
1006
1007
c (1 byte)
1008
1009
Note: This illustration considers the each padding (3 bytes) 1010
address is represented by 4 bits. 1011

Also note that in this example int is Total 12


occupying 4 bytes. Some compilers use 2 bytes
bytes for int, and some use 4 bytes.
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Another Example
struct test_struct {
char a; //1byte printf("a= %lu\n", sizeof(test.a)); = 1
short b; //2bytes printf("b= %lu\n", sizeof(test.b)); = 2
int c; //4bytes printf("c= %lu\n", sizeof(test.c)); = 4
} test; printf("%lu\n", sizeof(test)); = 8

a (1000) padding (1 byte) b(1002-1003)


c(1004-1007)

• We can notice that the padding added by compiler is less (only 1 byte), for the
same set of variable types, arranged with a different order in the structure.
• The total number of bytes to be added for padding is decided by the compiler
depending upon the arrangement of members inside the structure.

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Operations on struct variables

• Unlike arrays, group operations can be performed with structure


variables
• A structure variable can be directly assigned to another structure
variable of the same type
a1 = a2;
All the individual members get assigned
• You can’t do this for two arrays, without using “pointers”
• We will study about pointers in the next module
• You still can’t do equality check for two structure variables, i.e.
if (a1 == a2) is not valid in C
• You shall have to check equality for individual members

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Array of Structures
Once a structure has been defined, we can declare an array of
structures
Example:
struct book {
char Name[20];
float price;
char ISBN[30];
};
struct book bookList[50];

The individual members can be accessed as:


bookList[i].price à returns the price of the ith book.

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
BITS Pilani
Pilani Campus

Passing Structures to Functions


Passing struct variables to
functions
• A structure can be passed as argument to a function

• Structures can be passed both by pass by value and pass by


reference
• We will study about pass by reference later with “pointers”

• A function can also return a structure

• Array of structures are by default passed by reference


• Just like any other arrays.
• We will study later with pointers

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Example – Pass by value

#include <stdio.h> cmplx add(cmplx x,cmplx y){


typedef struct { cmplx t;
float re; t.re = x.re + y.re ;
float im; t.im = x.im + y.im ;
} cmplx; return (t) ;
}
int main() {
• When the function add() is
cmplx a, b, c; called, the values of the
scanf (”%f %f”, &a.re, &a.im); members of variables a and b
scanf (”%f %f”, &b.re, &b.im); are copied into members of
c = add (a, b) ; variables x and y.
printf (”\n %f %f”, c,re, c.im); • When the function add() returns,
} the values of the members of
variable t are copied into the
members of variable c.
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Example: Passing structure by
value illustrated
cmplx add(cmplx x,cmplx y) and c = add(a, b);

return (t)
x.re = a.re, x.im = a.im
y.re = b.re, y.im = b.im

c = t
c.re t.re
c.im t.im
t.re x.re + y.re
t.im x.im + y.im

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
BITS Pilani
Pilani Campus

Pointers in C
Addresses and Pointers
Consider a variable declaration in the Address
following program:
int main(){ a 5
1000
1001
int a = 5; 1002
} 1003
1004
1005
Say, the variable “a” occupies 2 bytes 1006
starting at memory location whose address is 1007
1000 (in hexa-decimal). 1008
1009
1010
This address can be accessed by “&a” 1011
printf(“Value of a: %d”,a); 5
printf(“Address of a: %p”,&a); 1000 Memory
allotted to
%p used to print addresses main()
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Addresses and Pointers
• The address of this variable a, can be stored in a Address
variable called a pointer variable
int * ptr = &a;
a 1000
5
1001
• ptr is a pointer variable of integer type. It is 1002
capable of storing the address of an integer 1003
variable. 1004
1005
• We can access the value stored in the variable a ptr 1000 1006
using ptr as well, by *ptr 1007
printf(“Value of a: %d”,*ptr); 5 1008
1009
1010
• *ptr translates to value at ptr. (de- 1011
referencing)
• Pointer variable of any type typically occupies 4 bytes
Memory
(or 8 bytes) in memory depending upon the
allotted to
compiler.
main()
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Simplifying with an example
Given declarations
int v;
int *p;
p = &v; is a valid assignment statement.
v 5

What is the effect of the following?


v = 5;

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Simplifying with an example…
Now, what is the effect of (*p)++ ?
v 5

(*p)++ is the same as


*p = *p + 1; p

*p (i.e., contents of p) is 5;

v 6

And it is changed to 6;
So v is also 6 p

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
BITS Pilani
Pilani Campus

Pointer Arithmetic
Pointer Arithmetic
• Incrementing a pointer
– NewPtr = CurrentPtr + N bytes
– Where N is size of pointer data type.

Example:
int a = 5;
int * p = &a; // assume &a = 1000
int * q = p + 1;
printf(“printing ptr: %p”, p); 1000
printf(“printing ptr: %p”, q); 1002

Incrementing ptr will increase its value by 2 as int is of 2 bytes.


What will be printed by the above print statements?
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Pointer Arithmetic
• Adding K to a pointer
– NewPtr = CurrentPtr + K * N bytes. We will see its
– Where K is a constant integer application when
we study arrays
– N is size of pointer data type. with pointers!

Example:
int a = 5;
int * p = &a; // assume &a = 1000
int * q = p + 4;
printf(“printing ptr: %p”, p); 1000
printf(“printing ptr: %p”, q); 1008

ptr will increase its value by 8 as int is of 2 bytes and 4*2 = 8


What will be printed by the above print statements?
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
BITS Pilani
Pilani Campus

Arrays and Pointers


Arrays and Pointers
int arr[4] = {1,2,3,4}; Addresses
• arr stores the 10010000
address of the first 10010001
10010010 arr
element of the array arr[0] = 1
10010011
• arr is actually a 10010100 arr+1
pointer variable arr[1] = 2
10010101
• arr+1 gives the arr+2
arr[2] = 3
address of the second arr+3
element arr[3] = 4
• difference between
arr and arr+1 is
actually 2 bytes
• arr+2 gives the
address of the third
element and so on…
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Arrays and Pointers
Accessing elements of arrays Addresses
arr[0] is same as *arr 10010000
arr[1] is same as 10010001
*(arr+1) 10010010 arr
arr[0] = 1
arr[2] is same as 10010011
*(arr+2) 10010100 arr+1
arr[1] = 2
… 10010101
arr+2
arr[2] = 3

Address of first element: arr+3


arr[3] = 4
arr or &arr[0]
Address of second element:
arr+1 or &arr[1]
Address of third element:
arr+2 or &arr[2]
and so on…
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Simplifying with an example
Given Ai
int Ai[100]; // array of 100 ints

Ai is the starting address of the array.

So, Ai[5] is same as *(Ai+5)

Observe that Ai+5 is “address arithmetic”:


address Ai is added to int 5
to obtain an address.

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Simplifying with an example
Given
Ai
int Ai[100];
int *pi;
pi

the following are valid:

pi = Ai

pi = Ai +2

pi – Ai which will evaluate to 2

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Example
int main(){
int *ptr, i, iA[5]={5,10,15,20,25};
for(i=0;i<5;i++)
printf("iA[%d]:address=%p data=%d\n", i, &iA[i], iA[i]);

//Accessing the Arrays using pointer


ptr = iA;
for(i=0;i<5;i++){
printf("\n pointer address = %p data = %d ", ptr, *ptr);
ptr++;
}
return 0;
}

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Array of Pointers
int main(){
int *ptr[3], i, iA[]={5,10,15}, iB[]={1,2,3}, iC[]={2,4,6};

ptr[0]=iA;
ptr[1]=iB;
ptr[2]=iC;

for(i=0;i<3;i++) {
printf("iA[%d]:addr=%p data=%d ",i,ptr[0]+i,*(ptr[0]+i));
printf("iB[%d]:addr=%p data=%d ",i,ptr[1]+i,*(ptr[1]+i));
printf("iC[%d]:addr=%p data=%d ",i,ptr[2]+i,*(ptr[2]+i));
}
return 0;
}

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
BITS Pilani
Pilani Campus

Pointers to Structures
Pointers to Structure

Consider the following structure definitions:

struct stud { struct book {


int roll; char Name[20];
float price;
char dept_code[25];
char ISBN[30];
float cgpa;
};
} class, *ptr;
struct book b, *br;

ptr = &class ü ptr = &b û


br = &b; ü br = &class; û

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Accessing members in pointers
to Structures
• Once ptr points to a structure variable, the members can be
accessed through dot(.) or arrow operators:

(*ptr).roll, (*ptr).dept_code, (*ptr).cgpa


OR
ptr–>roll, ptr–>dept_code, ptr–>cgpa

Syntactically,(*p).a is equivalent to p->a

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Illustration

struct stud {
int roll;
char dept_code[25];
float cgpa;
} class, *ptr;

roll Dept_code CGPA


class
1000

ptr = &class // ptr = 1000

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Caveats
• When using structure pointers, we should take care of operator
precedence.
• Member operator “.” has higher precedence than “*”
• ptr–>roll and (*ptr).roll mean the same thing.
*ptr.roll will lead to error
• The operator “–>” has the highest priority among operators.
• ++ptr–>roll will increment roll, not ptr
• (++ptr)–>roll will do the intended thing.

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
In General…
Do unary operators have the highest precedence?
– No. (), [], ., and -> have the highest precedence.
– So, *p->x is the same as *(p->x)
– Similarly, *p[n] is the same as *(p[n])
– By extension,
• *p->x++ is the same as *((p->x)++)
• ++*p[n] is the same as ++(*(p[n]))

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Pointers to Array of Structures
struct stud {
int roll;
char dept_code[25];
float cgpa;
} class[3], *ptr;

roll Dept_code CGPA


1000 Class[0]
1036 Class[1]
1072 Class[2]

ptr = class; // ptr = 1000, ptr+1 = 1036, ptr+2 = 1072

The assignment ptr = class assigns the address of class[0] to ptr


Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
BITS Pilani
Pilani Campus

Call/Pass by reference
Variable, Arrays and Structures
Swapping two variables using a
function: Attempt 1 – Pass by value
First Attempt: Pass by value
void swap(int x, int y){ int main(){
int temp = x; int a = 10, b = 20;
x = y; printf("Before Swapping %d %d\n", a, b);
y = temp; swap(a, b);
} printf("After Swapping %d %d\n", a, b);
return 0;
}

• The values of a and b get copied into x and y


• The swapping of x and y doesn’t get reflected back in a and b when
swap() function returns
• Also, we can’t return x and y to main() function as C supports return of a
single variable.

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Swapping two variables using a function:
Attempt 2 – Pass by reference
Second Attempt: Pass by reference
void swap(int *x, int *y) { int main() {
int temp = *x; int a = 10, b = 20;
*x = *y; printf("Before Swapping %d %d\n", a, b);
*y = temp; swap(&a, &b);
} printf("After Swapping %d %d\n", a, b);
return 0;
}

• The addresses of a and b get copied into x and y


• The swapping of *x and *y gets reflected back in a and b when
swap()function returns

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Passing Arrays into functions
Passing arrays into functions is by default call by reference.
void sort(int a[]) { int main() {
int temp, i , j, sorted = 0; int arr[8] = {2,5,9,7,1,5,4,6};
for(i = 0; i < SIZE-i-1; i++){
for(j = 0; j<SIZE-1-i; j++){ int SIZE = 8;
if(a[j] > a[j + 1]) printf(“Array before sort: \n”);
{ for (i = 0; i < SIZE; i++)
temp = a[j]; printf("%d ", arr[i]);
a[j] = a[j + 1];
a[j + 1] = temp; printf("\n");
} sort(arr);
} printf(“Array after sort: \n");
}
for (i = 0; i < SIZE; i++)
} printf("%d ", arr[i]);
When arrays are passed as printf("\n");
parameters, you pass the
return 0;
address of the first location
which the array variable name }

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Taking arrays as input
parameter
void sort(int a[]) { void sort(int * a) {
int temp, i , j, sorted = 0; int temp, i , j, sorted = 0;
for(i = 0; i < SIZE-i-1; i++){ for(i = 0; i < SIZE-i-1; i++){
for(j = 0; j<SIZE-1-i; j++){ for(j = 0; j<SIZE-1-i; j++){
if(a[j] > a[j + 1]) if(a[j] > a[j + 1])
{ {
temp = a[j]; temp = a[j];
a[j] = a[j + 1]; a[j] = a[j + 1];
a[j + 1] = temp; a[j + 1] = temp;
} }
} }
} }
} }

Both are equivalent…

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Example: Computing length of
a string
q Applications of Pointer arithmetic:
int strlen(char *str) {
char *p;
for (p=str; *p != ‘\0’; p++);
return p-str;
}
q Observe the similarities and differences with arrays.
int strlen(char str[]) {
int j;
for (j=0; str[j] != ‘\0’; j++);
return j;
}

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Pass by reference using
structures
typedef struct{ int main() {
int a;
float b; ST s1, s2;
} ST; s1.a=10; s1.b=10.555;
s2.a=3; s2.b=3.555;

void swap(ST * p1, ST * p2){ printf("s1.a:%d, s1.b:%f\n",s1.a,s1.b);


ST temp; printf("s2.a:%d, s2.b:%f\n",s2.a,s2.b);
temp.a = (*p1).a;
temp.b = (*p1).b; swap(&s1, &s2);
(*p1).a = (*p2).a;
(*p1).b = (*p2).b; printf("s1.a: %d, s1.b:%f\n",s1.a,s1.b);
(*p2).a = temp.a; printf("s2.a: %d, s2.b:%f\n",s2.a,s2.b);
(*p2).b = temp.b;
} }
Be careful of the precedence of “*”and “.” , with the latter having higher precedence.
You must use () if you want the operation to be correct
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Pass by reference using
structures (equivalent)
typedef struct{ int main() {
int a;
float b; ST s1, s2;
} ST; s1.a=10; s1.b=10.555;
s2.a=3; s2.b=3.555;

void swap(ST * p1, ST * p2){ printf("s1.a:%d, s1.b:%f\n",s1.a,s1.b);


ST temp; printf("s2.a:%d, s2.b:%f\n",s2.a,s2.b);
temp.a = p1->a;
temp.b = p1->b; swap(&s1, &s2);
p1->a = p2->a;
p1->b = p2->b; printf("s1.a: %d, s1.b:%f\n",s1.a,s1.b);
p2->a = temp.a; printf("s2.a: %d, s2.b:%f\n",s2.a,s2.b);
p2->b = temp.b;
} }

(*p1).a is equivalent to p1->a


Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Pass by reference using
structures (another equivalent)
typedef struct{ int main() {
int a;
float b; ST s1, s2;
} ST; s1.a=10; s1.b=10.555;
s2.a=3; s2.b=3.555;

void swap(ST * p1, ST * p2){ printf("s1.a:%d, s1.b:%f\n",s1.a,s1.b);


ST temp; printf("s2.a:%d, s2.b:%f\n",s2.a,s2.b);
temp = *p1;
*p1 = *p2; swap(&s1, &s2);
*p2 = temp;
} printf("s1.a: %d, s1.b:%f\n",s1.a,s1.b);
printf("s2.a: %d, s2.b:%f\n",s2.a,s2.b);

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Pointer to a Pointer
A pointer to a pointer is a form of multiple indirection, or a chain
of pointers.

Eg. int **ptr;

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
BITS Pilani
Pilani Campus

Stack vs Heap Memory


Welcome back our block
diagram!
• OS loads the
program executable
into the RAM
• Executes it line by
line on CPU

A line Program
from exe Program Executable (P1)
(exe)
Program is Compiled
executed Executable
Program of P1 (exe)
on CPU
CPU Executable gets
line by line
loaded into the
RAM

Memory (RAM) DISK


Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Looking at the main memory
only

Note: we
have flipped
Space our memory
allocated layout
to the our
program

Deeper view of space allocated to our program


Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Simplifying the layout of memory
allocated to our program

This is stack memory

This is heap memory

For simplicity, now on consider that we have only


TWO PARTITIONS of the memory allocated to our
program – STACK and HEAP
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Stack vs Heap
Stack:
• One frame allocated to each function call
• Auto (or local) variable defined inside the frame allocated for a
function
• Memory allocated to each frame is recalled after the function
execution finishes

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Illustrating stack memory
Stack When f1() returns, the
arr
memory allocated memory allocated to it is
1 2 3 4 recalled/erased.
to f1() in stack
So arr declared inside
memory allocated f1() does not exist
to main() in stack anymore. Accessing arr
in main function now
gives a run-time error.
Consider this program:
int f1(){
Heap int arr[4] = {1, 2, 3, 4};
return arr;}
uninitialized data segment
int main(){
int main_arr[] = f1();
printf(”First ele is: %d”, main_arr[0]);
return 0;}
text segment We can solve this if the array gets
Output:
memory allocated in the heap using
Memory allocated to our program seg fault dynamic memory allocation!
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Advantage of Heap over Stack
Stack:
• One frame allocated to each function calls
• Auto (or local) variable defined inside the frame allocated for
a function
• Storage allocated for each frame is recalled after the function
execution finishes

Heap:
• Heap is dynamically and explicitly allocated by programmer
• So allocated storage is not recovered on function return
• Programmer has to deallocate (at his/her convenience)
The memory allocated in heap is accessible globally to all functions

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
BITS Pilani
Pilani Campus

Dynamic Memory Allocation


Motivation
• Limitation of Arrays
– Amount of memory is fixed at compile time and cannot be modified.
• We tend to oversize Arrays to accommodate our needs.
– We can’t return an array from a function as the memory allocated to
the function gets destroyed on return.
Using malloc()
• Solution: and calloc()
– Allocate memory dynamically at run time. Using
• The size of the array can be taken as user input realloc()

• We can re-allocate the size of the array of it gets full


– Array gets memory in heap, hence can be accessed by all functions
of the program
Using free()
• Flexibility comes with a price:
– Programmer should free up memory when no longer required.
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Allocating memory
dynamically – malloc(): Syntax
<stdlib.h> is the header
file for using malloc() and
other dynamic memory
allocation related operations

#include <stdlib.h> Convert pointer to byte(s) (generic pointer)


void fun1() to the type pointer to int
{

int * pt = (int *) malloc (sizeof(int));


}

Ask Operating System to Number of bytes of memory


allocate memory required

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Creating a dynamically
allocated array

#include <stdlib.h>
#define MAX_SIZE 10
void fun2()
{

int * arr = (int *) malloc( MAX_SIZE * sizeof(int));


}

Number of bytes of memory


required

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
malloc()
Observations:
– Library stdlib provides a function malloc
– malloc accepts number of bytes and returns a pointer to a block of
memory
– Returned pointer must be “type-cast” (i.e. type converted) to required
type before use.
– malloc doesn’t initialize allocated blocks, each byte has a random
value.
– The block of memory returned by malloc is allocated in heap
Reading between the lines:
– Number of bytes is dynamic – unlike in arrays where size is constant.
– Can number of bytes be arbitrary?
• No! Memory is of finite and fixed size!

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Example
short * p1;
Pointer variable
int * p2; declaration
float * p3;

p1 = (short*) malloc(sizeof(short)); Allocating


p2 = (int*) malloc(sizeof(int)); memory to
p3 = (float*) malloc(sizeof(float)); pointer variable

*p1=256;
*p2=100; Assigning values
*p3=2.654;

printf(“p1 is %hd\n”, *p1);


printf(“p2 is %d\n”, *p2);
printf(“p3 is %f\n”, *p3)
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
BITS Pilani
Pilani Campus

Dynamically Allocated Arrays


Dynamically Allocated Arrays

Given pi
int *pi;
pi = (int *) malloc(N*sizeof(int));

Where does storage get allocated?


Not inside frames i.e., not inside call stack
But inside the heap

NOTE:
ü Usage syntax is same for static array locations and
dynamically allocated locations.
ü In both cases pointers are used internally.
ü Only difference is: static allocation vs. dynamic allocation
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Example
#include <stdio.h>
• This is not copying of array p into q.
#include <stdlib.h>
int main() {
• This means that the address
int *p,*q,i; contained in p is copied into q.
• Which means that now q also points
p = (int*) malloc(5*sizeof(int)); to first location of the array p.

q = p; // assigning array p to q

for (i=0;i<5;i++)
*p++ = i*i;
Both are equivalent
for(i=0;i<5;i++)
printf("Element at index %d is %d\n",i,q[i]);

// for(i=0;i<5;i++)
// printf("Element at index %d is %d\n",i,*(q + i));
}

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Dynamically Allocated Arrays
• We saw that arrays created inside a function could not be
returned.
– Since, arrays declared within a function are allocated in a
frame and they are gone when function returns.
• Solutions:
– Declare array outside function (in some other function) and
pass as parameter (only starting address is passed)
• Passed by reference, so changes get reflected in the calling
function.
– Or declare a pointer inside the function, allocate memory
and return the pointer.
• Since, memory is allocated in the heap, it will remain in the
calling function as well.
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Example: copy arrays - 1
The following program calls a function copy(), that copies the contents
of one array into another.
#include <stdio.h> int main()
#include <stdlib.h> {
int a[5] = {1,2,3,4,5};
void copy(int c[], int n, int d[]) int b[5];
{
for (int i=0; i<n; i++) copy(a,5,b);
{
d[i]=c[i]; for(int i=0;i<5;i++)
// or *(b+i)=*(a+i); {
} printf("%d\t",b[i]);
} }

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Example: copy arrays – 2
(using pointers)
#include <stdio.h>
#include <stdlib.h> Can be replaced with
int * a
int * copy(int a[], int n)
{
int * b = (int*) malloc(sizeof(int)*n);
for (int i=0; i<n; i++)
{
b[i]=a[i]; int main(){
// or *(b+i)=*(a+i); int a[5] = {1,2,3,4,5};
} int * b;
return b;
} b = copy(a,5);

for(int i=0;i<5;i++){
printf("%d\t",b[i]);
}
}
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Example: copy arrays – that is
incorrect (using pointers)
Solution:
#include <stdio.h>
• Allocate memory to b in
#include <stdlib.h>
main()and then pass. Try This!
• Allocate memory inside
void copy(int * a, int n, int * c)
copy()and return. (last slide)
{
• Use double pointer! (we will see
c = (int*) malloc(sizeof(int)*n);
later)
for (int i=0; i<n; i++)
{
c[i]=a[i]; int main(){
} int a[5] = {1,2,3,4,5};
} int * b;
Will lead to segmentation fault (run-time error). Why?
The contents of b were copied into c during function copy(a,5,b);
call. b was empty (or garbage value) when it was
passed. The memory that was allocated in copy() for(int i=0;i<5;i++){
function, its first element’s address is copied to c during printf("%d\t",b[i]);
the malloc()call. But this was not copied to b, when }
copy()returned. }
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
calloc()
• calloc()is used specifically for arrays and structures.
• It is more intuitive than malloc().
• Example:

int *p = calloc (5, sizeof(int));


// 2 arguments in contrast to malloc()

• The bytes created by calloc() are initialized to 0.

Note:
• After malloc(), the block of memory allocated contains garbage
values.
• malloc() is faster than calloc()

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
realloc()
What if the allocated number of bytes run out?
– We can reallocate!
– Use “realloc” from stdlib

int * pt = (int *)
realloc(pt,2*MAX_SIZE*sizeof(int));

realloc() tries to
• Enlarge existing block
• Else, it creates a new block elsewhere and move existing data to
the new block. It returns the pointer to the newly created block
and frees the old block.
• If neither could be done, it returns a NULL.

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Example
int *p, *q, *r, i;
p = malloc(5*sizeof(int));
q = p;

for (i=0;i<5;i++)
*p++ = i;
p = q;

printf("Array address %p \n", p);


r = realloc(p, 10*sizeof(int));
printf("Relocated address %p\n", r);
for(i=0; i<5; i++)
printf("The elements are %d\n", r[i]);

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Example

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
free()
• Block of memory freed using free() is returned to
Code the heap
• Failure to free memory results in heap depletion.
– which means that malloc() or calloc()
Static Data can return NULL saying that no more memory is
left to be allocated.
• free() syntax:
Stack

int * p = malloc(5*sizeof(int));

Free Memory
free(p);

Heap Releases all 5*sizeof(int) bytes allocated

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
BITS Pilani
Pilani Campus

Memory Management Issues


Memory Management Issues
Dangling Pointer:

#include <stdio.h>
#include <stdlib.h>
int main() {
int * p, *q, *r, i;
p = (int*) malloc(sizeof(int));
printf(“Address pointed by p = %p \n”, p);
free(p); // p becomes dangling pointer
printf(“Address pointed by p = %p \n”, p);
p = NULL;
printf(“Address pointed by p = %p \n”, p);
}

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Memory Management Issues
Memory Leaks: • p is made to point another memory block
without freeing the previous one.
• 1000*sizeof(int) bytes previously
allocated to p are now inaccessible.
• This is memory leak.

#include <stdio.h>
#include <stdlib.h>
int main() {
int * p, *q, *r, i;
p = (int*) malloc(1000*sizeof(int));
q = (int*) malloc(sizeof(int));
p = q;
} Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Memory Management Practices
In C programming it is the responsibility of the programmer to:
• keep freeing the allocated memory after its usage is over so
that malloc() and calloc() don’t fail.
• prevent memory leaks by careful programming practices
• Keep track of dangling pointers and re-use them.

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
BITS Pilani
Pilani Campus

Dynamically Allocated Array of Structures


Dynamically allocated struct
variable and array of structures
struct stud {
int roll; Rest of the operations are the same as
structures and array of structures.
char dept_code[25]; Only difference is that we have dynamically
float cgpa; allocated memory in the heap.

} class, *ptr;

struct stud * s1 = (struct stud*) malloc(sizeof


(struct stud));

struct stud * studentArray = (struct stud*)


malloc(sizeof(struct stud)*100);

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
BITS Pilani
Pilani Campus

Multi-dimensional Arrays using dynamic


memory allocation
Multi-dimensional arrays
2D arrays in stack memory:
#define NUM_ROWS 3 Notice the double
#define NUM_COLS 2 pointer
int arr2D[NUM_ROWS][NUM_COLS];

This array of 3 rows and 2 columns resides in stack and has all its problems that we
discussed earlier for 1D arrays

We can declare this array in heap dynamically at run-time by using a pointer to a


groups of pointers:

int ** arr2D = (int **) malloc(NUM_ROWS*sizeof(int*));


for (int i=0; i<NUM_ROWS; i++)
{
arr2D[i] = (int*) malloc(NUM_COLS*sizeof(int));
}
arr2D[1][2] = 10; // is a valid assignment

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
2D Array
#define NUM_ROWS 3
#define NUM_COLS 2
int ** arr2D = (int **) malloc(NUM_ROWS*sizeof(int*));

arr2D

Each of this blocks if the type int


*, i.e., each can hold address of
an int variable or the address of
the first location of an int array

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
2D Array (contd.)

for (int i=0; i<NUM_ROWS; i++)
{
arr2D[i] = (int*) malloc(NUM_COLS*sizeof(int));
}
arr2D

int arrays
of size
NUM_COLS
=2
Each of this blocks if the type int
*, i.e., each can hold address of
an int variable or the address of
the first location of an int array

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
2D Array (variable size)
One can define each array of variable size as well
arr2D[0] = (int*) malloc(sizeof(int)); // single int variable
arr2D[0] = (int*) malloc(sizeof(int)*3); // int array of size 3
arr2D[0] = (int*) malloc(sizeof(int)*5); // int array of size 5

int
arr2D variable

int arrays
of size 3

This was not possible int arrays


with static arrays of size 5

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Static vs Dynamic Arrays
Arrays (static) are Pointers in C?
– Well, not exactly …
– Arrays cannot be reallocated (starting address and size are
fixed).
– Multi-dimensional arrays (static) are not pointers to pointers.
• They are contiguous memory locations

int a[3][3];

a a+1 a+2 a+3 a+4


a[0][0], a[0][1], a[0][2], a[1][0], a[1][1],
a+5 a+6 a+7 a+8
a[1][2], a[2][0], a[2][1], a[2][2]

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Practice Questions – use pointer
notation only
• Write a C program that computes the transpose of a 2D
array.

• Write a C program that receives a 2D array and sorts the


elements by accessing the 2D array as a 1D array.

• Write a C program that receives a 1D array and an element


as input. Delete the element if it is present in the array and
shift the position of the remaining elements. The array is intact
if the element is not found.
• Observe the number of shifting required for various
elements, when the array is (a) sorted (b) unsorted.

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Remember our incorrect copy
arrays function…
#include <stdio.h> Solution:
#include <stdlib.h> • Allocate memory to b in main()
and then pass. Try This!
void copy(int * a, int n, int * c) • Allocate memory inside copy()
{ and return. (last slide)
c = (int*) malloc(sizeof(int)*n); • Use double pointer!
for (int i=0; i<n; i++)
(we will see NOW)
{
c[i]=a[i]; int main(){
} int a[5] = {1,2,3,4,5};
} int * b;
Will lead to segmentation fault (run-time error). Why?
The contents of b were copied into c during function copy(a,5,b);
call. b was empty (or garbage value) when it was
passed. The memory that was allocated in copy() for(int i=0;i<5;i++){
function, its first element’s address is copied to c printf("%d\t",b[i]);
during the malloc() call. But this was not copied to b, }
when copy() returned. }
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Example: copy arrays – that is
incorrect (using pointers)
#include <stdio.h>
Use of double pointer
#include <stdlib.h>
enables us to not return
void copy(int c[], int n, int ** d) {
anything, yet change getting
*d = (int *) malloc(n*sizeof(int));
reflected in main(). This is call
for (int i=0; i<n; i++)
by reference for dynamically
{
allocated arrays
(*d)[i]=c[i];
}
}
int main(){
int a[5] = {1,2,3,4,5};
int ** b = (int **) malloc(sizeof(int *));

copy(a,5,b);

for(int i=0;i<5;i++){
printf("%d\t",(*b)[i]);
}
} Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
BITS Pilani
Pilani Campus

Linked Lists - Motivation


Random Access List vs
Sequential Access List
Random Access List:
• Given a list of elements, you should be able to access any element
of the list:
• quickly
• easily
• without traversing any other element of the list
• Example: Using arrays to represent the list.
int arr[100] = {5,8,34,98,13,25,73,88,28,30};
5 8 34 98 13 25 73 88 28 30

• You can access 3rd element of the array by arr[2]


• This is quick, easy and doesn’t need one to traverse the entire
list to read the 3rd element
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Random Access List vs
Sequential Access List
Sequential Access List
• There is another way of representing lists where you should traverse
the list to reach any element of the list.

head

ele next ele next ele next ele next NULL

1st element 2nd element 3rd element 4th element


Accessing 3rd element

• To access 3rd element of the list you need to traverse 1st, 2nd elements
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Linked Lists
In other words, to access the value of 3rd element of
head
the list, you need to traverse the following nodes:
Head → 1st node → 2nd node → 3rd node

ele next ele next ele next ele next NULL

1st node 2nd node 3rd node 4th node


Accessing value stored at 3rd node

• Lists are now organized as a sequence of nodes, each containing a


• value of the element stored at that node: ele
All the nodes
• address of the next node: next together
• The head node contains the address of the first node represent a list
• The last node points to NULL, meaning end of the list or a sequence

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Linked List in Memory
• The nodes are not
sequentially arranged
in the memory
node1 ele next
• They are logically
connected with links

Illustrating a linked list of


head node3 ele next NULL
three nodes in the memory

node2 ele next


ele next ele next ele next

NULL

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Sequential Access Lists - Uses
Where are Sequential Access Lists useful?
• Create dynamic lists on run-time
• you can keep on adding nodes to the list, without bothering
about resizing the list, like in arrays when the number of
elements exceed their size
• Efficient insertion and deletion
• Without any shift operations
• Used to implement
• Stacks
• Queues
• Other user-defined data types

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
BITS Pilani
Pilani Campus

Linked lists Implementation


Linked Lists
head

ele next ele next ele next ele next NULL

1st node 2nd node 3rd node 4th node

To create linked lists we need two kinds of structures:


• One for storing the head
• The other to represent each node in the list
Let us see how each of these can be defined…
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Self referential structures
Before we see the structure definition of linked lists, let us see
what self-referential structures are:

“Self-referential structures contain a pointer member that


points to a structure of the same structure type”
Self-referential
structures
Wrong Declaration essentially store
Correct Declaration
a pointer
struct self_ref struct self_ref variable to of its
{ { own type to
reference to
int data; int data;
another structure
struct self_ref b; struct self_ref *b; variable of its
}; }; kind.

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Linked Lists
count head stores the address of the first node
count stores the number of nodes/elements in the list
head
ele in each node stores the element (integer in this case)
next stores the address of the next node in the list

ele next ele next ele next ele next NULL

1st node 2nd node 3rd node 4th node

Consider that our linked list stores integer elements.


struct node{ struct linked_list{
int ele; int count;
struct node * next; struct node * head;
}; };
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
BITS Pilani
Pilani Campus

Linked List Implementation with


Dynamic Memory Allocation
Creating linked list using
malloc()
typedef struct node * NODE; typdef struct linked_list * LIST;
struct node{ struct linked_list{
int ele; int count;
NODE next; NODE head;
}; };

LIST createNewList(){
LIST myList;
myList = (LIST) malloc(sizeof(struct linked_list));
// myList = (LIST) malloc(sizeof(*myList));
myList->count=0;
myList->head=NULL; myList count=0
return myList;
head=NULL
}

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Creating new node
typedef struct node * NODE; typdef struct linked_list * LIST;
struct node{ struct linked_list{
int ele; int count;
NODE next; NODE head;
}; };

NODE createNewNode(int value){


NODE myNode;
myNode = (NODE) malloc(sizeof(struct node));
// myList = (NODE) malloc(sizeof(*myNode));
myNode->ele=value;
myNode->next=NULL; myNode ele=value
return myNode;
} next=NULL

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Inserting a node into the list
void insertNodeIntoList(NODE n1, LIST l1){
// case when list is empty
if(l1->count == 0) { count=0 10
l1->head = n1; head NULL next NULL
n1->next = NULL;
l1->count++;
}
// case when list is non empty
else {
... ... count=1
} head
10
}
next NULL

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Inserting a node into the list
(contd.)
void insertNodeIntoList(NODE n1, LIST l1){
// case when list is empty
if(l1->count == 0) {
... ...
} Insertion is usually done at
// case when list is non empty the beginning of the list.
else { It is very fast. Doesn’t
n1->next = l1->head; require any traversal or
l1->head = n1; shifting of elements
l1->count++;
} n1 10
}
next NULL

count=3 4 10 30 25
l1 head
next next next NULL

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Inserting a node at the end of
the list
void insertNodeAtEnd(NODE n1, LIST l1){
// case when list is empty
This case is same as insert at
if(l1->count == 0) {
the beginning of an empty
l1->head = n1; list.
n1->next = NULL;
l1->count++;
}
// case when list is non empty
else {
... ...

}
}

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Inserting a node at the end of
the list
void insertNodeAtEnd(NODE n1, LIST l1){
... ...
// case when list is non empty • Traverse the list until the end.
else { • Insert new node at the end
NODE temp = l1->head;
while(temp->next!=NULL)
{
temp = temp->next;
}
temp->next = n1;
n1->next = NULL;
l1->count++; n1 10

} next NULL
}
count=3 4 10 30 25
l1 head
next next next NULL

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Inserting a node after a given
node
void insertAfter(int searchEle, NODE n1, LIST l1){ else{
// case when list is empty if(temp->next == NULL) {
… … temp->next = n1;
// case when list is non-empty n1->next = NULL;
else { l1->count++;
NODE temp = l1->head; }
NODE prev = temp; else {
while(temp!=NULL) { prev = temp;
if (temp->ele == searchEle) temp = temp->next;
break; prev->next = n1;
prev = temp; n1->next = temp;
temp = temp->next; l1->count++;
} }
if(temp==NULL) { return;
printf("Element not found\n"); }
return; }
} return;
}

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Removing a node from the
beginning of the list
void removeFirstNode(LIST l1)
{
if (l1->count == 0)
{
printf("List is empty. Nothing to remove\n");
}
else
{
NODE temp = l1->head;
l1->head = temp->next;
temp
free(temp);
l1->count--;
}
10
return; next
}
count=3 2 30 25
head
l1 next next NULL

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Removing a node from the end
of the list
void removeLastNode(LIST l1) else
{ {
if (l1->count == 0) NODE temp = l1->head;
{ NODE prev = temp;
while((temp->next) != NULL)
printf("List is empty\n");
{
}
prev=temp;
else if(l1->count == 1)
temp = temp->next;
{ }
l1->count--; prev->next = NULL;
free(l1->head); l1->count--;
l1->head = NULL; free(temp);
} }
return;}

count=3 2 10 30 25
l1 head
next next NULL next NULL
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
main()
int main(){
LIST newList = createNewList();
NODE n1 = createNewNode(10);
NODE n2 = createNewNode(20);
NODE n3 = createNewNode(30);

insertNodeIntoList(n1,newList);
insertNodeIntoList(n2,newList);
insertNodeAtEnd(n3,newList);

NODE n4 = createNewNode(40);
insertAfter(10,n4,newList);

removeFirstNode(newList);
removeLastNode(newList);
}

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Other functions
Exercise: Implement the following functions for a linked list:

• search(int data, LIST mylist): returns the node that contains its
ele=data
• printList(LIST mylist): prints the elements present in the entire list in
a sequential fashion
• removeElement(int data, LIST mylist): removes the node that
has its ele=data
• isEmpty(LIST mylist): checks if the list is empty or not
• Modify the insert/delete functions to first check whether the list is empty using
isEmpty() function.

In each of the above, you must have to decide which one is an appropriate
datatype for the same.

Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
BITS Pilani
Pilani Campus

You might also like