Skip to content

Allocating Memory

With dynamic memory management, one of the tasks you can perform is to request space from the heap. With this request, the operating system will locate available space and allocate this to you for use in your code. The only thing the operating system really needs to know is how much space you require? It can then search for a free space of that size, allocate this to you, and then give you the address of (a pointer to) this newly allocated area of memory.

Figure x.y: When requesting a memory allocation you need to specify the size you want

When requesting a memory allocation you need to specify the size you want

Memory Allocation: Why, When, and How

If you want to load a value onto the heap, you use these memory allocation functions to allocate you space. Once you have the space allocated, you can access it via the pointer you receive back from the functions.

In C/C++

C includes two memory allocation functions: malloc, and calloc. Let’s see how each of these work.

FunctionRequired ArgumentsReturnsDescription
mallocthe size in bytes that you want.a pointer (void *)Allocates memory and returns a pointer to it.
callocthe number of items, and the size of each itema pointer (void *)Allocates and clears memory, returning a pointer to the space allocated.

These functions are used in combination with the sizeof operator. You can use sizeof to get the number of bytes that a data type or variable requires.

Operator: sizeof
Returns: (size_t) the number of bytes for a type
Parameter: a type or expression

Allocate memory with malloc

The malloc function is declared within stdlib.h. It has the following function prototype.

void *malloc(size_t size)

malloc is the standard memory allocation function in C. You tell it how much space you want, it allocates you that many bytes on the heap, and returns a pointer to that address.

The following example demonstrates the use of malloc to store an integer value on the heap. In this case we use malloc to allocate sufficient space to store an integer on the heap. The sizeof operator can give us the size of an integer, which we can then pass to malloc to ensure we ask for the right number of bytes. The result returned from malloc is a void pointer (an untyped pointer), so we need to cast this to be an int pointer (int *).

#include <stdlib.h>
#include <stdio.h>
int main()
{
int *p;
// get space for one integer from the heap
p = (int *)malloc(sizeof(int));
// Access the data from the heap
printf("The value on the heap is %d.\n", *p);
// Assign the value 10 to the space on the heap
*p = 10;
// Access the data from the heap
printf("The value on the heap is now %d.\n", *p);
// free all sapce allocated
free(p);
p = nullptr;
return 0;
}
Example calls to malloc

The program begins at main() and line 3 declares an int pointer variable
Line 4 will allocate some memory space on the heap by calling the malloc() function, and return a pointer to this memory region which we can use to initialize the variable p. Let's break line 4 down into steps. The first thing malloc() needs is an argument which specifies how much memory needs to be allocated in bytes. Because we are creating space for an integer, we call the sizeof(int) function, which will return the size of an integer on our system (often this will be 4 bytes, but it depends on your computer). We then pass this value as an argument to malloc() (step 4a)
At step 4b, malloc() is called and memory is allocated on the heap for an integer. The initial value of the integer isn't guaranteed by malloc(). As you can see here, it happens to have allocated a region of memory where the bits have an integer value of 5155. NOTE: We've shown the bit-representation of an integer to help you see the actual low-level memory allocation that is performed in this step. The last thing to note here is that malloc() will return a void pointer...
Because malloc() returns a void pointer, we need to cast it to the type of pointer our variable will hold, in this case an int pointer (step 4c). Now that we know these bytes are an int, the value at that location in memory is 5155
The last step of line 4 (step 4d) is the assignment step. The address of the memory space that has been allocated on the heap is copied into the variable p
Line 5 prints the value of p to the terminal. Remember that p is a pointer variable so it holds the address of a memory space on the heap
Line 6 prints the dereferenced value of p to the terminal. Remember that when we dereference a pointer using the *p notation, what we are doing is getting the address stored in the pointer, then finding the value at that location in memory (in this case 5155)
Line 7 assigns the dereferenced value of p, the new value of 10. Once again remember that dereferencing a pointer using the notation *p means that we are dealing with the value at the location of the memory address (not the memory address value itself). You can see that the value has changed from 5155 to 10 on the heap
Line 8 prints the new dereferenced value of p to the terminal
Line 9 calls the <strong>free</strong> function, passing it the pointer p. This will free the space allocated on the heap for the memory area that was allocated to the pointer p. NOTE: however, that although the area on the heap is deallocated and available for use by other code within our program, the value of our pointer p has not changed and is still pointing to that area (it's a dangling pointer)
...this means that when we print the value of p, it will still show the same address of the memory area that was in use before (but now deallocated)
To avoid problems with any later use of variables that have acted as pointers, the best practice is to reset the value of p to a NULL value. We do this by assigning p> the value nullptr, which is a which is a a built in constant that is a shorthand for a null pointer
This time when we print the value of p, we can see that it has been reset to null, by printing 0
Finally we hit the return statement, and control returns to our caller, ending our program

Allocate memory with calloc

Like malloc, calloc is used to allocate space on the heap. The difference between calloc and malloc is that calloc clears the memory allocation. This will ensure that each byte in the space allocated is set to 0. Whereas, with malloc any previous values that happen to have been in memory will remain there giving the value a seemingly random value.

The other difference with calloc is that you pass it both a number, and a size. This allows you to allocate arrays easily with calloc, as it returns you a pointer to a block of memory that is number x size bytes.

#include <stdlib.h>
#include <stdio.h>
int main()
{
int *p;
// get space for one integer from the heap
p = (int *)calloc(1, sizeof(int));
// Access the data from the heap - will always be 0 as it was cleared
printf("The value on the heap is %d.\n", *p);
// Assign the value 10 to the space on the heap
*p = 10;
// Access the data from the heap
printf("The value on the heap is now %d.\n", *p);
// free all sapce allocated
free(p);
p = nullptr;
return 0;
}
Example calls to calloc
The program begins at main() and line 3 declares an int pointer variable
Line 4 will allocate some memory space on the heap by calling the calloc() function, and return a pointer to this memory region which we can use to initialize the variable p. Let's break line 4 down into steps. At step 4a, the first thing calloc() needs is two arguments which specifies how much memory needs to be allocated in bytes. Because we are creating space for a single integer, we specify: 1 for as the first argument to calloc() which says that we want space for one integer.Then as the second argument we call the sizeof(int) function, which will return the size of an integer on our system (often this will be 4 bytes, but it depends on your computer)calloc() will use these two arguments to calculate how much memory space needs to be allocated
At step 4b, calloc() is called and memory is allocated on the heap for an integer. You can see that once calloc() has allocated the memory, there is initially a residual value left over in the memory area where the space was created... NOTE: We've shown the bit-representation of an integer to help you see the actual low-level memory allocation that is performed in this step. The last thing to note here is that calloc() will return a void pointer...
At step 4c, after calloc() has allocated memory space, it will overwrite the memory region allocated with zeros, guaranteeing that the we will always start with a 0 in any memory area allocated by calloc()
Because calloc() returns a void pointer, we need to cast it to the type of pointer our variable will hold, in this case an int pointer (step 4d). Now that we know these bytes are an int, the value at that location in memory is 0
The last step of line 4 (step 4e) is the assignment step. The address of the memory space that has been allocated on the heap is copied into the variable p
Line 5 prints the value of p to the terminal. Remember that p is a pointer variable so it holds the address of a memory space on the heap
Line 6 prints the dereferenced value of p to the terminal. Remember that when we dereference a pointer using the *p notation, what we are doing is getting the address stored in the pointer, then finding the value at that location in memory (in this case our initial value of 0)
Line 9 assigns the dereferenced value of p, the new value of 10. Once again remember that dereferencing a pointer using the notation *p means that we are dealing with the value at the location of the memory address (not the memory address value itself). You can see that the value has changed from 0 to 10 on the heap
Line 8 prints the new dereferenced value of p to the terminal
Line 9 calls the <strong>free</strong> function, passing it the pointer p. This will free the space allocated on the heap for the memory area that was allocated to the pointer p. NOTE: however, that although the area on the heap is deallocated and available for use by other code within our program, the value of our pointer p has not changed and is still pointing to that area (it's a dangling pointer)
...this means that when we print the value of p, it will still show the same address of the memory area that was in use before (but now deallocated)
To avoid problems with any later use of variables that have acted as pointers, the best practice is to reset the value of p to a NULL value. We do this by assigning p> the value nullptr, which is a which is a a built in constant that is a shorthand for a null pointer
This time when we print the value of p, we can see that it has been reset to null, by printing 0
Finally we hit the return statement, and control returns to our caller, ending our program