A lot of people have trouble grasping manual memory management when they first encounter it. The syntax can be a little confusing and debugging can be an extremely painful process - whether you have a segfault or Valgrind is complaining that you still have memory leaks.
Using pointers in C, while a little intimidating at first, is not as difficult as most people expect.
C gives you a lot of access to memory - you can allocate bytes for use in your program, you can deallocate them, you can directly access memory addresses in your program, and pass them around wherever you want. The possibilities are endless!
A brief overview
So what exactly is a pointer?
A pointer is an operator in C that lets you “point” to a particular location in memory. With a pointer, you can directly manipulate memory and pass references to the same location in memory to multiple functions, to directly modify variables in other functions, or just avoid unecessarily making a copy of a parameter to save memory.
To illustrate this, let’s pretend we have an array of integers:
arr is an array of integers. Each element takes up some space in memory.
In C, arrays are all contiguous, so every element is next to each other
in memory. We can represent this in array in memory as such:
| 0x0 | 0x1 | 0x2 | 0x3 | 0x4 | | 0 | 1 | 2 | 3 | 4 |
We can access the second element in arr in two diferent ways:
Because ptr points to the second element of arr, adding 1 to it brings it from
address 0x0 to 0x1, which is where you will find 1.
You can pass this pointer to other functions as well, and directly modify this array without returning/copying over a new array.
Syntax
We will first start by defining the syntax and necessary functions that you need to allocate memory, declare pointers, get the address of a function, and free the memory that you have allocated.
Operators
In C, you have two operators that pertain to memory management: & and *.
The * allows you to declare a pointer variable type. If you use the * on
a pointer after it has already been declared, you will get the value that it
references. This is called dereferencing. The & operator returns the address
of a variable, so it will return a pointer to the variable it is being used on.
Here is an example of the operators in action:
Functions
There are two functions that you have to know to use memory management in C:
malloc and free. malloc allocates a block of memory. It takes an
argument which tells it how much memory to allocate (in bytes).
free is called on a variable that has been initialized by malloc -
it frees the memory that was being used. You want to free this memory
up to be reclaimed by the operating system so you can avoid memory
leaks.
You will also want to make sure that everything that has been malloc’d
is also free’d, and that you don’t free a block of memory that has
already had free called on it.
Here are the references for malloc and free.
These functions are found in stdlib.h, so if you are using these
functions in your C program, you will have to prepend the file with
#include <stdlib.h>.
There is a very helpful macro in C called sizeof. Note that I mentioned
earlier that malloc takes the number of bytes to allocate as an argument.
How do we know how many bytes to allocate for an array of ints,
a double, or a char? sizeof returns the size of the type in bytes,
which makes it very convenient to use with malloc. Let’s look at how we
can use sizeof
You can use sizeof with custom structs, and even for pointers themselves
Suppose you wanted to create an array of arrays. You’d do so like this:
This gives us an array of 4 arrays where each array has 4 elements.
Usage
Let’s take a look at an example that utilizes the functions and operators that were just discussed.
This covers some of the basics of allocating and deallocating memory in C. Stay tuned for a primer on using GDB/LLDB and Valgrind.