As we have seen in our earlier discussions, arrays in C must have a defined size while declaring them in the program. This is not true for modern programming languages. This memory related paranoia in C programming seems absurd in this age where even mobile phones have GigaBytes of RAM. But in early 70’s, when C was developed, computer memories were very small. The first commercially available DRAM chip, the Intel 1103, introduced in October 1970, had 1024 bits of memory, i.e. 128 bytes of memory! The first Apple product, the Apple I computer had 2kB memory and most microcomputers (desktops) had 16kB to 64kB of memory even in early 80’s.
To put that in perspective let us take an example. Consider that an organisation of 3000 employees needs to sort their employees by name. Since names have variable number of letters, they are stored in arrays of 32 characters to support long names. To sort the names, all the names should be loaded into memory. It will require 3000 x 32 bytes of RAM, i.e. 96000 bytes i.e. about 94kB. In this modern age of Gigabytes it seems very little, but back then computers would crash trying to sort names of employees of an organisation or students of a university.
That is why C puts the responsibility of managing memory on the programmers. Programmers would anticipate memory requirement and write programs accordingly. Even so, there are real-life scenarios where memory requirement cannot be anticipated beforehand and there is a need of allocating memory while a program is running. The process of allocating memory while a program is running is called dynamic memory allocation. In C programming, dynamic memory allocation is achieved with the standard library functions malloc(), calloc(), realloc() and free(). Lets take a look at each of them.
Malloc: The name malloc stands for “memory allocation”. This function takes as argument, the number of bytes to be allocated, and returns a void pointer, pointing to the first byte. This pointer can then be type-casted to be of the required type. In case enough memory is not available, a NULL pointer is returned. Lets look at an example.
These Dynamic Memory Allocation (DMA) functions are defined in the header file stdlib.h. First we initialize the required variables.
- length: The user defined length of the array of numbers.
- i: This is used in the for loops.
- numbers: This is an int pointer which will hold the value returned by malloc.
In line 8 we ask the user to input the required length of the array and store it in the length variable. Then we allocate a memory size of the length multiplied by size of an int type variable. The malloc() function returns a void pointer, but we need an int pointer for our array, so we type-cast it into an int pointer and assign it to numbers.
If sufficient memory is not available, this numbers will have a value of NULL in it, i.e. the pointer will point to nowhere. We check this condition in line 15 and exit out if true. Otherwise we take the input from the user in a for loop. Note that incrementing a pointer increments the address by the number of bytes specified by its datatype. Thus if a character pointer points to address 1001 and it is incremented by 1, the value will be 1002. But for an integer pointer which points to 1001, increment by 1 will result in new address of 1004. In the for loop, we successively store the numbers by incrementing numbers by i. Note that this line can also be written as:
While displaying we can prove that it is an actual array by using array notation in the print statements. As we see in the output, the memory got allocated correctly. But if we declare the size in the mallac() function to be greater than the available memory, it will not be able to allocate that. It is illustrated in the following example.
Calloc: The name calloc stands for “contiguous allocation”.The only difference between malloc() and calloc() is that, malloc() allocates single block of memory whereas calloc() allocates multiple blocks of memory each of same size and sets all bytes to zero. If we take a look at the same example using calloc() function, there is not much difference in them.
Only in line 9, we can see that calloc() function takes two arguments, the number of blocks and the size of each block.
The rest of the program is exactly the same. You can run the program yourselves and check the output.
Free: Dynamically created memory doesn’t get free till the program terminates. Thus if these memory blocks are unused and other programs running on the computer needs more memory, they may get crashed. So the standard library also provides a function to free the dynamically allocated memory that we no longer need. This is the free() function, as we see in line 28 of the previous example. It takes in one argument, which is the pointer to the allocated memory.
Realloc: If we need to change the size of the allocated memory at any point in the program, we can use the function realloc(). It takes two arguments, the first is the pointer to the previously allocated memory, and the second is the new size in bytes. Its syntax is:
ptr = realloc(ptr, new_size);
We will use dynamic memory allocation excessively in our upcoming sections where we’ll discuss structures and linked lists. You can download the code here.
If you liked this article please comment and show your support and interest so that I’ll be motivated to continue this effort. Like our facebook page if you haven’t already. And if you have any questions please comment. I’ll try to reply all.