C++ - C++ Pointers - Programming Languages

Our Guide to C++ Pointers

Pointers are so fundamental to programming that virtually all languages have them, C++ included. While pointers are highly effective, they’re also complex to work with. Let’s dive in and understand what they’re all about. 

What Is a Pointer in C++?

Unlike a normal variable which may hold a value of a type like int or char, a C++ pointer is a variable that stores the memory location of another variable. It might be helpful to think of a pointer as a shortcut on a desktop. A pointer stores the address of another variable and thus also gives us a way to access and change the contents of the pointed-to variable.

As you begin to gain proficiency in C++, you’ll see that just like any other variable in the language, a pointer variable is declared before it can be used. A pointer declaration must include an asterisk before the name of the pointer. Here’s an example:

int hoop = 8;      //line 1 - assign the variable
int* ptr_var;      //line 2 - declare a pointer to an integer variable
ptr_var = &hoop;   //line 3
*ptr_var = 10;     //line 4

As you can see, line 3 retrieves the address of hoop and places it inside ptr_var. This is done through the use of the reference operator &, inserted before the variable name. While it’s used in other contexts to denote different meanings, a variable preceded by an & means that we’re retrieving the variable’s address. 

Moving on to line 4, it’s important to note that using an asterisk as a dereference operator can cause some confusion. This time, the asterisk preceding the pointer name is used to “dereference” or access the value of the variable that ptr_var is pointing to. This value is modified to 10. If we were to now print the variable hoop, the output would be 10.

Here, it’s important to go over the NULL pointer. A pointer initialized to a NULL value means the pointer is not pointing to anything. Dereferencing a NULL pointer will give you an exception. C++11 introduces a new keyword named nullptr to initialize pointers to a NULL value: 

int *ptr { nullptr };

Why Are Pointers Used in C++?

Pointers in C++ are useful for several reasons. A big consideration for any programmer is the efficient use of memory. Pointers make it possible to dynamically access and manipulate memory. With pointers, we can structure memory access in custom ways. For example, we can use custom data structures that do not otherwise fit into standard variable declarations. Another example is efficient memory access for high-performance applications. 

Pointers are valuable because they allow us to increase program execution speed. This results in simpler code, especially as the size of our code increases.

For example, we can use pointer variables to modify and return by function, a much better alternative to passing-by-value. Without pointers, we would have to manually copy values, thus ending up with bulkier code. This works fine when working with a single integer but can be more complex when working with a more advanced data structure. Let’s take a look at an example:

void createArray(int *array_name, int num)
{
    for (int x = 0; x < num; x++)
        array_name[x] = x+1;
 }
int main()
{
    int array[4];
    int* foo = array;
    createArray(array, 4);
    for (int i = 0; i < 4; ++i) {
        cout << *foo[i] << “ “;
    }
    return 0;
} //Output: 1 2 3 4 

As we saw above, pointers can also be used to point to, access and manipulate the contents of a dynamic data structure like an array. While pointers and arrays are not the same, an array name functions as a pointer. Here, foo points to the first element of the array.

Pointers also uniquely allow for pointer operations or pointer arithmetic. You can compare pointers not only for equality, but also perform arithmetic operations like <  and <=. You can even add integers to pointers and subtract one pointer from another. 

Alternatives to Pointers in C++

While pointers offer advantages like reducing code complexity and saving memory, drawbacks like potential memory leaks generally make them best to avoid. Instead, developers often opt for references or smart pointers.  

Reference Pointer

Although references have more constraints and are less powerful when compared to “raw” pointers, they are still preferred whenever possible due to safety and ease of use.

Unlike the pointer variable, a reference variable is simply another name for a preexisting variable. A reference variable must be initialized and does not allow for reassignment like pointers, thus eliminating wild pointers. A reference can be used to access the value of the variable pointed to, without the need for any extra syntax as is the case with pointers.

Let’s take a look at an example:

#include<iostream>
using namespace std;

int main()
{
  int coconut = 4;
  int& ref = coconut; //ref is a reference to coconut
  ref = 5;            // Value of coconut is now changed to 5
  cout << "coconut = " << coconut << endl ;
  coconut = 10;       // Value of coconut is now changed to 10
  cout << "ref = " << ref << endl ;
  return 0;
}
   //Output: 
   //coconut = 5
   //ref = 10

While pointers are useful at times, references are generally preferable. For instance, when handling data structures like linked lists and trees, a raw pointer, which allows for reassignment, is clearly preferred to the reference pointer. 

By contrast, references are preferable when using functions. A pass-by-reference value can access and modify the original variable that a reference points to, thus allowing for changes made inside the function to be reflected globally, as well. 

Smart Pointer

As indicated by the name, smart pointers are more efficient than their counterparts. They have the functionality of pointers but eliminate the key drawbacks to using pointers: manual memory management and memory leaks. 

In C++, smart pointers are implemented as template classes that wrap a pointer and automate certain functionality. Smart pointers are always initialized as either NULL pointers or pointers to a heap object. When a pointer is no longer in use, the memory it points to is automatically deallocated. 

C++11 introduced three types of smart pointers: the unique pointer, the shared pointer and the weak pointer. Each of these is defined in the <memory> header from the Standard Library.

Let’s look at a simple example to see how the unique pointer might work:

void calculate()
{
    std::unique_ptr<int[]> hoopla = std::make_unique<int[]>(30);
    //some calculation is done on hoopla
}
     // When the function reaches the end of its body, hoopla goes out of
     // scope and is automatically destroyed by invoking the destructor.
int main( )
{
    calculate( );
}

Pointer to Pointers

While a regular pointer refers directly to a memory location, a double pointer is a variable that points to another pointer, which in turn points to a memory location. Double pointers are used when we wish to preserve the memory allocation or assignment outside of a function. C++  developers do not frequently use the double pointer any longer.

A double pointer is declared using two asterisks instead of one. Here’s an example:

int var = 50;
int* var_ptr = &var;
int** value_double_ptr = &var_ptr;

Become a C++ Developer

There’s no escaping pointers if you want to become a C++ programmer. Pointers provide increased visibility, which makes for more powerful programming.

To build on the fundamentals we covered above, we invite you to check out our expert-taught C++ Nanodegree program. As part of this specialized program, you’ll get practical C++ experience by coding five real-world projects. Continue your C++ journey today! 

<p><a class="btn btn-primary" href="https://www.udacity.com/course/c-plus-plus-nanodegree--nd213" target="blank" rel="noopener noreferrer">Start Learning</a></p>