0% found this document useful (0 votes)
27 views26 pages

2.1 - Dynamic Memory Allocation

The document discusses Dynamic Memory Allocation (DMA) in programming, contrasting it with static memory allocation. It explains how to use functions like malloc, calloc, and realloc for allocating and managing memory dynamically, including examples of dynamically allocated arrays and structures. Additionally, it highlights the importance of properly freeing allocated memory to avoid memory leaks.
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)
27 views26 pages

2.1 - Dynamic Memory Allocation

The document discusses Dynamic Memory Allocation (DMA) in programming, contrasting it with static memory allocation. It explains how to use functions like malloc, calloc, and realloc for allocating and managing memory dynamically, including examples of dynamically allocated arrays and structures. Additionally, it highlights the importance of properly freeing allocated memory to avoid memory leaks.
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/ 26

Dynamic Memory Allocation

(DMA)
Dr. Tanvir Ahmed
Static Vs Dynamic Memory Allocation
• So far our example declared variables and array were
statically allocated memory.
• It means there allocated spaces are not changing.
• In regards to memory allocation the word static and
dynamic has the following meaning:
• Static:
– the memory requirements are known at compile time.
– after a program compiles, we can perfectly predict how much
memory will be needed
– Whether you take input or not, still that memory spaces will be
used
– Any statically allocated variable can only have its memory
reserved while the function within which it was declared is
running.
– For example, if you declare an int x in function F1, if function F1
has completed, no memory is reserved to store x anymore.
Static vs Dynamic Memory Allocation
• Dynamic:
• the memory requirements are NOT known at
compile-time.
• Memory allocation size may vary based on
different execution as it may depends on input.
• Dynamically allocated memory isn’t “freed”
automatically at the end of the function within
which it’s declared (although it is not accisible
automatically from another function)
• This shifts the responsibility of freeing the
memory to the programmer.
• This can be done with the free function.
malloc, calloc functions
• Malloc or calloc function can be used to
dynamically allocate memory
• Malloc:
– void *malloc(size_t size);
– It allocates unused space for an object whose size
in bytes is specified by size
– The value is unspecified in malloc
– returns a pointer to the beginning of the memory
allocated.
– If the memory can’t be found, NULL is returned.
malloc, calloc functions
• Calloc:
– void *calloc(size_t nelem, size_t elsize);
– It allocates an array of size nelem with each element of size
elsize
– returns a pointer to the beginning of the memory
allocated.
– The spaces shall be initialized to all bits 0
– If the memory can’t be found, NULL is returned.
• Basically in both function you have to say how many
bytes to allocate (how to specify is different).
• Then, if the function successfully finds the memory it
returns the pointer to the beginning of the block of the
memory returned.
• If unsuccessful, NULL is returned.
Dynamically Allocated Arrays
• Sometimes you don’t know how big an array you will need
until-runtime.
• You can dynamically allocate memory in those cases.
• int *ptr1 = (int*) malloc(10*sizeof (int));
• Remember that malloc and calloc return void pointers
(void*). So, if you want to use the allocated memory as an
array, you must cast the array to the type you want. Why?
• The above line could be written in multiple lines:
int *ptr1;
ptr1 = (int*) malloc(10*sizeof (int));
Now ptr1 can be treated as an array and you can iterate
through it!
-What values are stored in the array?
• ptr1 = (int*) calloc(10, sizeof (int));
• How about the values of the ptr1 now if you use calloc?
• See the uploaded code.
Example malloc and calloc
void main() ptr2 = (int*) calloc(10, sizeof
{ (int));
int *ptr1 = (int*) if (ptr2 == NULL)
malloc(10*sizeof (int)); //why are {
we casting? printf("Could not allocate
int *ptr2; memory\n");
exit(-1);
int i;
}
if (ptr1 == NULL) else
{ {
printf("Could not allocate printf("Memory allocated. Printing
memory\n"); data after calloc: \n");
exit(-1); for(i=0; i<10; i++)
{
}
printf("%d ", ptr2[i]);
else //it will print 0 for all elements
{ }
printf("Memory allocated. }
Printing data: \n"); free(ptr1);
for(i=0; i<10; i++) free(ptr2);
printf("%d ", }
ptr1[i]); //it will print garbage
values
}
//due to lack of space, the next
lines are shown in the right side
Some notes to remember
• malloc and calloc allocates specified amount of bytes
• returns void*
• So, cast them so that you can iterate through it or let it
know what type of data are you going to refer with
this.
• Additional notes: In recent compilers you can skip
casting, because your program will cast it automatically
based on the target pointer type
• Think about you have an array of structure type data?
• Let’s say you have a structure called Student with name
and score. How would you allocate and create an array
of N students?
• Struct Student *students;
• students = (struct Student*) malloc(N*sizeof (struct
Student));
There is a risk of creating memory leak!
• Consider the following lines of code:
int *ptr1 = (int*) malloc(10*sizeof (int));
int *ptr2 = (int*) malloc(10*sizeof (int));
ptr1= ptr2;

• Can you find any problem in the above piece of code?


• After the line ptr1=ptr2, you code does not have any
access to the memory allocated by first malloc that was
assigned to ptr1. But still that memory is being used by
your code. It is called memory leak.
• So, we have to be careful while working with dynamic
memory allocation so that our code does not create
any memory leak.
realloc
• There might be cases when the allocated array size is not enough
and you will need to resize the array.
• How would you approach this?
• Naïve approach would be:
– Allocate new memory
– Copy the old data to the new allocated array
– Free the old array.
• We can avoid extra work through realloc function.
• void *realloc(void *ptr, size_t size);
• So here, ptr is the old pointer, and size is the new size.
• It will allocate size amount of bytes and copy the content from the
allocated data in ptr and return void pointer.
• Let’s say values is an integer pointer and already allocated to
numVals size. The following line will reallocate.
• values = (int*)realloc(values,(numVals+EXTRA)*sizeof(int));
• See uploaded example.
#include <stdio.h>
Example of realloc
#include <time.h> values =
#define EXTRA 10 (int*)realloc(values,(numVals+EXTRA)*
int main() { sizeof(int));
int numVals;
srand(time(0)); for (i=0; i<EXTRA; i++)
printf("How many numbers?\n"); values[i+numVals] =
scanf("%d", &numVals); rand()%100;

int* values = numVals += EXTRA;


(int*)malloc(numVals*sizeof(int));
int i; for (i=0; i<numVals; i++)
for (i=0; i<numVals; i++) printf("%d ", values[i]);
values[i] = rand()%100;
for (i=0; i<numVals; i++) printf("\n");
printf("%d ", values[i]);
printf("\n"); free(values);
return 0;
//see the right side for remaining }
lines of the code

//output
How many numbers?
5
97 62 7 74 48
97 62 7 74 48 44 23 75 61 64 69 92 39 23 58
Process returned 0 (0x0) execution time : 3.112 s
Dynamically allocating array in function
• The key idea is very similar to doing this task in main, but you have to return
a pointer to the array created.
• You have to free the pointer in main function.
• Example:

int* readArray(int size) {


int* p = (int *)malloc(size*sizeof(int));
for (i = 0; i<size; i++)
scanf("%d", &p[i]);
return p; p
}

How to call it from the main function?


printf(“How many numbers?:”);
scanf(“%d”, &size);
int* numbers = readArray(size);

//after performing all the operation on numbers, free it


free(numbers);
Dynamically allocated structure from a function
• We will create the following struct and return a pointer to it from a
function: struct integer {
int* digits;
int size;
};
• Now we want to dynamically allocate memory for an integer structure.
How can we do that?
– struct integer* temp;
temp = (struct *integer) malloc(sizeof(struct integer));

• Next, we want to dynamically allocate memory for the digits which will
be an array of int with size number of elements. How can we do that?
– temp->digits = (int *) malloc(numDigits*sizeof(int));
• The memory allocation picture will be like this:

int*digits
int size
size
• Now, if we want to do it from a function, what should you return?
• How the function signature should look like?
Dynamically allocated structure from a function
• We will create the following struct and return a pointer to it from a
function: struct integer {
int* digits;
int size;
};
• The following function creates a random struct integer dynamically and returns a
pointer to it:
struct integer* createRandBigInt(int numDigits) {
struct integer* temp;
temp = (struct *integer) malloc(sizeof(struct integer));
temp->digits = (int *) malloc(numDigits*sizeof(int));
temp->size = numDigits;
temp->digits[numDigits-1] = 1 + rand()%9;
int i;
for (i=0; i<numDigits-1; i++)
temp->digits[i] = rand()%10;
return temp;
}

• So, let’s see the code: How many mallocs in the above code? What are their purpose?
• First one allocated space for the struct iteself. This space is just for one integer pointer (small
amount space) and one integer.
• The second malloc allocates space for the array (this is potentially a large amount of space).
How would you free the memory for
the example
• To properly free the memory from this whole
structure,
• imagine we had a variable p of type struct
integer* pointing to a struct integer.
• These two lines would be necessary to free
all the memory for the structure:
free(p->digits);
free(p);
How to create a dynamically allocated
array of structs from a function
• Very similar to allocating an int array dynamically. Only
difference is it is struct type instead of int.
struct point {
• Example structure: int x;
int y;
};

• We want to create something like this, where the size is


dynamic:
int x int x int x int x int x
temp
int y int y int y int y int y

size
• So, how can we do that?
– struct point* temp;
temp = (struct point*)malloc(size*sizeof(struct point));
How to create a dynamically allocated
array of structs from a function
• Very similar to allocating an int array dynamically. Only
difference is it is struct type instead of int.
struct point {
• Example structure: int x;
int y;
};
• The following function takes array size and max value of x and y to be
generated. Then it dynamically allocate array point filled with random
values. Then returns a pointer that points the the fron of the array.
struct point* createRandPoints(int size, int maxVal) {
struct point* temp;
temp = (struct point*)malloc(size*sizeof(struct point));
int i; #Once the space is allocated, we treat
for (i=0; i<size; i++) { each array location as an individual
temp[i].x = 1 + rand()%maxVal; struct, using . to access its components.
temp[i].y = 1 + rand()%maxVal;
} #To free this array, if we had a pointer
my_pts pointing to the array, do the
return temp;
following: free(my_pts);
}
Creating a dynamically allocated array of pointers to structs
• It would be very similar to the previous example, but this time, our array
elements will only store a POINTER to the struct instead of the struct
itself.
• So, our picture will be like the following picture. temp
• So, what type of array is it? temp[0]
point*
– What is the size of that array?
– What type of variable is the temp? point* temp[1]

– What can we store inside the array element? point* temp[2]


– Can we use each of them for dynamic memory allocation?
…. …
• So, temp is an array of structure pointer.
…. …
– It means, each element of the array will be a pointer
– So, making temp as a simple structure pointer would not have the power to point* temp[siz
hold address of another pointer e-1]
– It means temp has to be a a pointer of pointer
– The equivalent lines of code for the following picture is this: int x
– struct point** temp;
temp = (struct point**)malloc(size*sizeof(struct point*));
int y
• Now, we have an array of point pointers and we can use each of
them to allocate memory for many points as we wish. int x
• It means, each temp[i] can be another array! int y
• But in our example, we will just allocate one structure for each
of them
int x
• temp[i] = (struct point*)malloc(sizeof(struct point));
int y
How to create a dynamically allocated array of
pointers to structs
• So, the function will look like this
struct point** createRandPoints(int size, int maxVal) {
struct point** temp;
temp = (struct point**)malloc(size*sizeof(struct point*));
int i;
for (i=0; i<size; i++) {
temp[i] = (struct point*)malloc(sizeof(struct point));
temp[i]->x = 1 + rand()%maxVal;
temp[i]->y = 1 + rand()%maxVal;
}
return temp;
}

- First, notice the double pointer – the first is for the array, the second is for the
contents of each array element. (Note: This same declaration could be used for a 2-D
array…). Our first allocation is for the array. From there, for each array element, we
must allocate space for each individual struct. Finally, notice the use of the -> since
temp[i] is a pointer.
How would you free the memory for the last example?

• We must free everything in the same fashion (each element first,


then the array). Here is some code to show this process:

temp
struct point** my_pts = createRandPoints(100,
point* temp[0]
1000);
// Do something with my_pts. point* temp[1]

// Frees each individual point pointer. point* temp[2]


int i;
for (i=0; i<100; i++) …. …

free(my_pts[i]); …. …
// Frees the memory that stores the main array.
point* temp[siz
free(my_pts); e-1]
How to dynamically allocate a two
dimensional array
• Here is some code that allocates a two dimensional array of integers (or
rather, an array of an array of integers) with n rows and m columns.
Assume that n and m are integer variables that have already been given
meaningful values.
int** array = (int**)malloc(sizeof(int*)*n);
int i;
for (i=0; i<n; i++)
array[i] = (int*)malloc(sizeof(int)*m);

• Notice that the first cast is to int** and second set of casts are to int*.
• These are the types of array and array[i], respectively.
Also note that we need sizeof(int*) in the first malloc, since array will be an array
of int*, but we need sizeof(int) for the second set of mallocs, since each array[i]
will be an array of integers.

Now, here is how we free this memory:


for (i=0; i<n; i++)
free(array[i]);
free(array);
Dynamic memory allocation for an array of Strings
• Consider you have a file with words.
• The first line says how many words will
be there and the next lines contain the
words. temp
• Example: char* ‘cat’
5 char* ‘blackCat’
string1
char* ‘whiteCat’
string2
string3
…. …
string4
String5 …. …
• Now you want to write a function to char* ‘grayCat’
read the strings and print them.
• We want to use dynamic memory
allocation for storing the array of string
and also for storing the string by
dynamically allocating memory.
Dynamic memory allocation for an array of Strings

• Let us see our main function: int main() {


• Why we need double pointer?
• Because we want to store an char fileName[50];
char** pList;
array of string, where: int numWords;
– The size of the array is
dynamic // Get the filename.
printf("Enter the file name.\n");
– Each element in the array is a scanf("%s", fileName);
string which will be
dynamically allocated // Read in the list storing it in pList.
• What are we passing to // numWords will store the number of
words in the file.
readList function? pList = readList(fileName, &numWords);
– Can you write the signature of
the function? // Print these words to check that our
read worked and free the memory.
– See, we are passing printList(pList, numWords);
&numWords to the function freeList(pList, numWords);
• Why we do that? return 0;
• Because we want it to get }
updated in the function (pass by
reference!)
Dynamic memory allocation for an array of Strings

• Why we don’t char** readList(char* fileName, int* wordsCount) {


have & here? char** pList = NULL;
• Why we have * char word[MAX_STRING_LENGTH];
here? int i, wordLength;
• As WordsCount
itself a pointer, FILE* pFile = fopen(fileName, "r"); // open file.
which actually
changing if (pFile != NULL){
everything to /* read the 1st line, get to know how many words in the dictionary. */
numWords fscanf(pFile, "%d", wordsCount);
/* Here we allocate space a pointer for each word in the list. Note that the
variable in main space for the words themselves is NOT allocated here. */
function. pList = malloc(*wordsCount * sizeof(char *));
• Why are we
adding 1? for (i = 0; i < *wordsCount; i++){
• So, this code // read in this word.
reads each string fscanf(pFile, "%s", word);
from the file and // Allocate one extra spot for the null character.
allocate memory wordLength = strlen(word) + 1;
for that string into // Allocate space for this individual word.
our array and pList[i] = malloc(wordLength*sizeof(char));
store it like the // copy the word to the memory block.
picture in the last strcpy(pList[i], word);
slide, }
fclose(pFile); // close file.
}
return pList;
}
- The full code is available in webcourses.
Reference
• Arup’s note on dynamic memory allocation:
http://www.cs.ucf.edu/~dmarino/ucf/transpar
ency/cop3502/lec/DynMemAlloc.pdf

You might also like