Summary: in this tutorial, you will learn about C dynamic memory allocation mechanism and how to use C built-in functions to allocate memory.
Introduction to C Dynamic Memory Allocation
In C, the memory is managed statically, automatically or dynamically.
The static-duration variables are stored in the main memory and exist during the program execution.
The automatic-duration variables, which you define in the function, are allocated on the stack. The automatic-duration variables are only available during the function execution.
Both static-duration and automatic-duration variables are required to allocate memory at the compile-time, which is seldom practical especially for large data objects.
Fortunately, C provides a dynamic memory allocation mechanism that allows you to allocate memory at run-time. C gives you some useful functions, e.g., malloc()
,
realloc()
, calloc()
and free()
that help allocate memory based on the program’s needs.
Getting size of types using sizeof operator
Before allocating memory to a data object, you need to identify its size to allocate the corresponding amount of memory.
To get the size of any data type e.g., int, float, array, structure, etc., you use the sizeof
operator. The sizeof
operator returns an amount of storage in bytes for any type.
The return type of the sizeof
operator is size_t
that is a separate type in C to represent amounts of memory.
C uses a separate type size_t
because the existing types are defined based on the target processor’s arithmetic capabilities, not the memory capabilities.
The size_t
is unsigned
defined in the stddef.h
header file. The maximum value of the size_t
is defined as a macro constant ( SIZE_MAX
) in the stdint.h
file. It is at least 65535
.
For example, to get the size of integer type, you use the following expression:
sizeof(int);
Code language: C++ (cpp)
It returns 4 bytes in typical 32-bit machines.
The following program displays the sizes of common C data types.
#include <stdio.h>
#include <stdlib.h>
typedef struct _address{
int house_number;
char street[50];
int zip_code;
char country[20];
} address;
int main()
{
printf("Size of int is %d bytes\n",sizeof(int));
printf("Size of unsigned int is %d bytes\n",sizeof(unsigned int));
printf("Size of short is %d bytes\n",sizeof(short));
printf("Size of unsigned short is %d bytes\n",sizeof(unsigned short));
printf("Size of long is %d bytes\n",sizeof(long));
printf("Size of char is %d bytes\n",sizeof(char));
printf("Size of float is %d bytes\n",sizeof(float));
printf("Size of double is %d bytes\n",sizeof(double));
printf("Size of address is %d bytes\n",sizeof(address));
return 0;
}
Code language: C++ (cpp)
Allocating memory
C provides you with three functions for allocating memory: malloc()
, realloc()
and calloc(). Also, it gives you the free()
function for releasing memory which is no longer used.
Using the malloc() function
The prototype of the malloc()
function is a follows:
void * malloc(size_t size);
Code language: C++ (cpp)
The malloc()
function allocates a block of memory with the size specified by the size_t
. It returns It returns a pointer to the allocated memory. If the memory could not be allocated or the size
argument is 0, the malloc()
function returns NULL.
The following example demonstrates how to use the malloc()
function to allocate memory:
int* pi; int size = 5; pi = (int*)malloc(size * sizeof(int));
The sizeof(int)
returns the size of an integer
, which is 4 bytes, and multiply with 5
so the pi
pointer is pointing to the first byte of 5 * 4 = 20
bytes memory block.
You should always check the return pointer from the malloc()
function for NULL. See the following example:
#include <stdio.h>
#include <stdlib.h>
int main()
{
const int SIZE = 100;
int* pi;
pi = (int*)malloc(SIZE * sizeof(int));
if(pi == NULL)
{
fprintf(stderr,"error occurred: out of memory");
exit(EXIT_FAILURE);
}
/* further processing */
/* ... */
free(pi);
return 0;
}
Code language: C++ (cpp)
Notice that the block of memory allocated by the malloc()
function is uninitialized. If you want to initialize memory, you use the memset()
function after allocating memory or use calloc()
function.
You should always call free()
function to release the allocated memory. We will discuss the free() later in the below section.
Using the calloc() function
The function header of the calloc()
function is as follows:
void * calloc (size_t n, size_t size);
Code language: C++ (cpp)
The calloc()
function allocates memory much like malloc()
function except the following differences:
- When you call the
calloc()
function, you need to pass 2 parameters: the first one specify the number of elements and the second one specify the size of each element. The product of these parameters determines the size of the memory block is allocated. - The memory block allocated by the
calloc()
function is initialized to zero.
The following example demonstrates how to use the calloc()
function to allocate memory for a dynamic array:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int *a, *pa;
int i, size;
printf( "Enter the size of the array:\n" );
scanf( "%i", &size);
a = (int*)calloc(size, sizeof(int));
if(a != NULL)
{
pa = a;
for (i = 0; i < size; ++i)
*pa++ = rand();
for (i = 0; i < size; ++i)
printf( "a[%d] = %d\n", i, a[i] );
}
else
{
perror( "Out of memory!!!" );
abort();
}
free(a);
}
Code language: C++ (cpp)
The following is the output:
Enter the size of the array:15
a[0] = 41
a[1] = 18467
a[2] = 6334
a[3] = 26500
a[4] = 19169
a[5] = 15724
a[6] = 11478
a[7] = 29358
a[8] = 26962
a[9] = 24464
a[10] = 5705
a[11] = 28145
a[12] = 23281
a[13] = 16827
a[14] = 9961
Code language: PHP (php)
Using realloc() function
The realloc()
function allows you to change the size of the memory block allocated by the malloc()
or calloc()
function.
void* realloc (void* ptr, size_t size);
Code language: C++ (cpp)
The realloc()
function the size of the memory block pointed by the ptr
pointer. See the following example:
#include <stdio.h>
#include<stdlib.h>
int main()
{
int len1, len2;
char *buffer;
char *s1 = "0 1 2 3 ";
len1 = strlen(s1);
printf("%s(%d)\n",s1,len1);
len1 = len1 + 1; /* for \0 */
buffer = (char *)malloc(len1 * sizeof(char));
if(buffer == NULL)
{
printf("Out of memory!!!\n");
exit(1);
}
strcpy(buffer,s1);
printf("The buffer is: %s(%d)\n",buffer,strlen(buffer));
char *s2 = "4 5 6 7 8 9";
len2 = strlen(s2);
printf("%s(%d)\n",s2,len2);
buffer = (char *)realloc(buffer, (len1 + len2) * sizeof(char));
if(buffer == NULL)
{
printf("Out of memory for the buffer!!!\n");
exit(1);
}
strcat(buffer,s2);
printf("The buffer is: %s(%d)\n",buffer,strlen(buffer));
free(buffer);
}
Code language: C++ (cpp)
Using the free() function
Memory is a limited resource. Therefore, you should always deallocate or release the memory back when it is no longer used. To deallocate the memory that you have allocated, you use the free()
function.
To use the free()
function, you just need to pass a valid pointer to it. If you pass a NULL pointer, the free()
function does nothing. If you accidentally call the free()
function twice to deallocate the same memory block, the free()
function will deallocate the memory block at the first call and does nothing at the second call.
#include <stdio.h>
#include <stdlib.h>
int main()
{
const int size = 100;
int* p[size];
int i;
printf("allocate memory...\n");
for(i = 0; i < size; i++)
{
p[i] = (int*)malloc(sizeof(int));
}
/* further processing */
printf("deallocate memory...\n");
for(i = 0; i < size; i++)
{
free(p[i]);
}
return 0;
}
Code language: C++ (cpp)
In this tutorial, we have introduced you to C dynamic memory allocation and how to use some handy functions in the C library function to allocate and deallocate memory.