C/C++ Pointers

If you are looking for C/C++ tips, please review the Programming Practice and Methods article.

Pointers are a basic data type found in the C/C++ programming language as well as in other languages. It's a powerful tool used for low-level memory access that may be used for many purposes. Simply, a pointer is a data type that contains (or in other terms 'points to') an address in memory. A pointer may be associated with a data type for correct data access, but in reality all pointers are the same structure in memory. A pointer is always the same size as the system's addressing scheme. A 32-bit architecture will have 32-bit addressing, which means pointers will be 4 bytes large.

Purpose
Pointers are useful for memory manipulations as well as useful for keeping the location of memory allocated in the heap. The C/C++ run-time has two large sections of memory called the stack and the heap. The stack is a section of memory that grows and shrinks based on variables defined in a function. If a program calls a function that uses two integers in it's code, the stack will grow by two integers. When the function finishes, the two integers are no longer needed the stack shrinks back to its original size. This system is created so that memory is efficiently used and manages itself, based on the concept that memory allocated by a function call is released when the function is finished.

Issues arise when the programmer needs a variable to persist even after the function has finished. A special section of memory called the heap is designed for persistent data. This section must be managed by the programmer in terms of allocation and release. This data can only be accessed by pointers since it is simply just a section of memory. Another reason why heap allocated memory is special is because it is the only type of memory that may be allocated of given sizes at run-time. This means that at run-time, you may allocate a certain amount of memory that could not be predicted at compile-time.

Usage
The syntax for declaring a pointer is as follows:

(type) *(variable name)[ = initial address];

This might seem overly complex but is in-fact easy to follow: The type is the type of data the pointer will point to. If you were to create a pointer that points only to integers you would use the int keyword. The variable name is the name of this variable. This is exactly like declaring a normal variable in C/C++, except there must be a star (*) symbol before the variable name to declare this as a pointer type. Like standard variables, you may choose to initialize the variable or leave it uninitialized. So, a new pointer to a character would be:

The initial value may be set to a static address (hard coded), to NULL (Which is considered a default non-existent address), or to an address of an object. To get the address of an object use the ampersand (&) symbol before the target variable.

Here are a few examples:

A pointer may use basic C/C++ algebraic operators, such as '+=', '=', '==', '--', and more. These are used to change the value of the pointer (what the pointer points to). These are powerful tools when working in arrays or strings. Note that C/C++ does not do bounds checking for performance reasons, so it is up to you as the programmer to make sure you never read or write to a location that is invalid.

Memory Allocation
One of the main usages of a pointers is for heap memory allocation. The benefit of heap allocation is that you manage when the data is created, how long it exists, and the size is defined at run-time.

For C heap allocation, use the function void *malloc(size_t size); which returns a pointer to the newly allocated memory. Note that the parameter size is in bytes. If the function fails, it will return NULL. To release allocated memory, use the void free(void* data) function.

In C++ use the new (data type)[ [size of elements] ] keyword to allocate data. Note that unlike the C function malloc, the new keyword allocates sizes by calculating the needed bytes itself. Use the delete keyword to release data. Do not forget to use the delete[] keyword when releasing an array of data.

It is important to remember to always release memory after usage so that future heap allocations may use that space. Losing the address of the allocation, thus loosing the possibility of freeing the data, is called a memory leak.

A C example:

A C++ example:

A C++ array example:

Accessing Pointer Data
Once a pointer is pointing to a valid space in memory it is important to know how to access the space. A pointer variable by itself is strictly the address, but by using the special star (*) operator, you dereference the address, presenting the data. In other words, by placing the * operator in front of a pointer, you begin working with the contents, not the address.

Accessing members of custom data types (such as structs/classes) is more challenging. Imagine we have an object called Person and this object has the member Age which is an integer and the function SetAge(int NewAge). Using standard C/C++ operators, we would use the dot-operator to access these members such as Person.SetAge(21). Now imagine if PersonPointer were a pointer to this Person object. By using the dereference operator * we can get the original contents of the Person object such as *PersonPointer.SetAge(21). This unfortunately is incorrect due to operator precedence. Using the correct order of operators, you would write: (*PersonPointer).SetAge(21).

C/C++ provide a special operator as a short-hand form of the above syntax. The arrow operator -> allows you to apply the dereference operator correctly without the tedious syntax. The above example can be written as: PersonPointer->SetAge(21).

Arrays and Pointers
In C/C++, array variables are actually pointers to the first element of the array and the "[]" array access operators are pointer manipulators. This means that when you create an array, the variable name is a pointer of the base address. By adding x to the base address, you offset yourself to each element x. The following code demonstrates this:

Simply, the array element access operator "[]" takes the given index and applies the appropriate offset needed to access data. The reasoning is that the variable name for the array is the address of the first element of the array (called the base address) which is the exact same type as a pointer. By manipulating this pointer (such as offsetting it), we can access the appropriate element since arrays contain the elements as a series, growing by a positive address.

(array name)[(index)] = (new value); is equivalent to *( (array name) + (index) ) = (new value);

Some examples include:

x[y] = z is equivalent to *(x + y) = z myList[3] = 5 is equivalent to *(myList + 3) = 5

Segmentation Faults
In languages with unmanaged memory, such as C/C++, segmentation faults are common errors. A segmentation fault occurs when your program's process reads or writes out of bounds. Prevent this by always defaulting non-initialized pointers to NULL, checking if a pointer is valid when given as a parameters, and checking all memory allocation.