DSA - CP Revision
DSA - CP Revision
Fundamentals - DSA
BITS Pilani Jagat Sesh Challa
Pilani Campus
BITS Pilani
Pilani Campus
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
BITS Pilani
Pilani Campus
2. What happens to your program when you try to compile and run it?
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
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?
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?
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
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)
• Character (char)
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
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;
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
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
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
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]
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.
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
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
• 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
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];
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
BITS Pilani
Pilani Campus
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Example – Pass by value
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
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Simplifying with an example…
Now, what is the effect of (*p)++ ?
v 5
*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
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
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Simplifying with an example
Given
Ai
int Ai[100];
int *pi;
pi
pi = Ai
pi = Ai +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]);
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
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:
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Illustration
struct stud {
int roll;
char dept_code[25];
float cgpa;
} class, *ptr;
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;
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;
}
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;
}
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;
} }
} }
} }
} }
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;
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.
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
BITS Pilani
Pilani Campus
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
Note: we
have flipped
Space our memory
allocated layout
to the our
program
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
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Creating a dynamically
allocated array
#include <stdlib.h>
#define MAX_SIZE 10
void fun2()
{
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=256;
*p2=100; Assigning values
*p3=2.654;
Given pi
int *pi;
pi = (int *) malloc(N*sizeof(int));
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:
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;
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);
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
BITS Pilani
Pilani Campus
#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
} class, *ptr;
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
BITS Pilani
Pilani Campus
This array of 3 rows and 2 columns resides in stack and has all its problems that we
discussed earlier for 1D arrays
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
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
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];
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.
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
head
• 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
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
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
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
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;
}; };
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