Module 11 - Dynamic Memory Allocation
Module 11 - Dynamic Memory Allocation
Allocation
BITS Pilani Dr. Ashutosh Bhatia & Dr. Asish Bera
Pilani Campus
Department of Computer Science & Information Systems
Module Overview
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
Memory
allocated to
the our Heap Segment
program
Data Segment
Text Segment
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
Let us try to explain with our
memory diagram
Stack frame allocated to When f1() returns, the memory
main_arr
main() in stack allocated to it is destroyed.
Stack
int main(){
int main_arr[] = f1();
printf(”First ele is: %d”, main_arr[0]);
Text
return 0;
}
Memory allocated Output:
to our program Error!
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
#include <stdlib.h>
Convert pointer to byte(s) (generic pointer)
void fun1() to the type pointer to int
{
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 (of type void)
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=123.456;
Given pi
int *pi;
pi = (int *) malloc(N*sizeof(int));
N elements
Where does storage get allocated?
Not inside frames i.e., not inside call stack
But inside the heap
NOTE:
✓ Usage syntax for the array and its elements is the same for
static arrays (arrays on stack) and dynamically allocated
arrays.
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. (previous 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
Stack Segment the heap
• Failure to free memory results in heap depletion.
– which means that malloc() or calloc()
can return NULL saying that no more memory is
left to be allocated.
• free() syntax:
Heap Segment
int * p = malloc(5*sizeof(int));
Data Segment
…
free(p);
Text Segment
Releases all 5*sizeof(int) bytes allocated
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 to another memory block without freeing
the previous one.
• 1000*sizeof(int) bytes previously allocated to p are
now inaccessible.
• This is a memory leak. Leaked memory can be recovered
only after the program terminates.
#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
Another example of a memory
leak
#include <stdio.h>
#include <stdlib.h>
int main() {
int * p, *q, *r, i;
for (i=0;i<1000000;i++)
{
p = (int*) malloc(10000*sizeof(int));
q = (int*) malloc(sizeof(int));
}
// some more lines of code
...
}
40,000 bytes are allocated and wasted for each iteration of this loop
(considering sizeof(int) is 4 bytes)
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Memory Leak (Consequences)
• Memory leaks reduces the performance of the computer by
reducing the amount of available memory.
• In the worst case, too much of the available memory may become
allocated and all or part of the system or device stops working
correctly, the application fails, or the system slows down vastly.
• Memory leaks are particularly serious issues for programs like
daemons and servers which by definition never terminate.
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
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Grocery Store Case:
readGroceryItems()
struct item * readGroceryList(int count){
struct item * gItems = (struct item *) malloc(sizeof(struct
item)*count);
int uniqNum = 1;
return gItems;
}
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Grocery Store Case:
printGroceryList()
void printGroceryList(struct item * gItems, int count)
{
for (int i = 0; i < count; i++)
{
printf("Item ID: %d, ", gItems[i].ID);
printf("Name: %s, ", gItems[i].name);
printf("Price: %f, ", gItems[i].price);
printf("Quantity: %d\n", gItems[i].quantity);
}
}
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Grocery Store Case:
findItem()
struct item findItem(int qVal, struct item * gItems, int count)
{
int i = 0; int index = -1;
while(i<count)
{
if(gItems[i].quantity == qVal)
{
index = i;
return gItems[index];
}
i++;
}
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Grocery Store Case:
findMaxPriceItem()
struct item findMaxPriceItem(struct item * gItems, int count)
{
int maxIndex = -1;
int maxPrice = -1;
int i = 0;
while(i<count)
{
if(gItems[i].price > maxPrice)
{
maxPrice = gItems[i].price;
maxIndex = i;
}
i++;
}
return gItems[maxIndex];
}
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Grocery Store Case:
main()
int main(){
int num_g;
printf("Enter number of unique grocery items in the store:");
scanf("%d",&num_g);
struct item * gItems = readGroceryList(num_g);
printGroceryList(gItems,num_g);
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Grocery Store Case:
main() (contd.)
int main(){
... // contd. from previous page
int qVal;
printf("\nEnter the quantity of the item you wish to find: ");
scanf("%d",&qVal);
struct item fItem= findItem(qVal,gItems,num_g);
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Sample Execution
Enter number of unique grocery items in the store:3
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 array
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
Exercises
• 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
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Example 1
int main(int argc, char *argv[]) Notice the change
{
printf(“Number of arguments: %d \n", argc);
int i = 0;
while(i < argc){
printf("Argument %d: %s \n",i, argv[i]);
i++;
}
return 0;
}
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
Example 2
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int a, b, c;
a = atoi(argv[1]);
b = atoi(argv[2]);
c = atoi(argv[3]);
printf("\n %d",a+b+c);
return 0;
}
Dept. of Computer Science & Information Systems, BITS Pilani, Pilani Campus
BITS Pilani
Pilani Campus