C++ Tutorial: Pointers and Memory

May 31st, 2015


In this tutorial, we will cover the basics of how pointers and computer memory works. We will begin by looking at variables at both an abstract level and a low level. We will briefly cover how computer memory works. Finally, we will go over how pointer variables work.

Variables

At a high level, variables are containers that store data. At a low level, variables are named allocations of memory. If a variable is like a box, then a data type is like a box size, and the data is content.

A char variable, for instance, takes up one byte of memory. An int variable takes up four bytes. A double takes up eight bytes. While the contents of a variable can change during program runtime, the variable does not change. It keeps the same data type and the same allotment of memory for its lifetime.

Or course, some variables can be created and destroyed during runtime. These variables are called dynamic variables and they are assigned using a special kind of data type we call a pointer.

We will go over pointers in a moment. First, we will go over how variables are created, destroyed, and managed.

Memory Management

In C and C++, there are two times in which variables are created. The first time is when the program compiles. The second time is when the program runs.

After you write a program, the compiler translates the code into machine­-level instructions. Those instructions are then loaded into the computer’s memory. Finally, those instructions are fed into the processor so that they can be executed in sequence.

Variables that are created during compile time will occupy a fixed amount of memory for the duration of the program. These are “safe” variables since they are assigned free space during compile time. Thus, they won’t overwrite memory cells that are currently in use.

Dynamic variables, which are created during runtime, are not so safe. When you create a dynamic variable, you could assign it to any memory address and, therefore, accidentally overwrite something important.

Furthermore, since “garbage collection” in C++ is not automatic, you have to programmatically deallocate your dynamic variables. Otherwise, you could clog up the memory and cause a stack overflow. When a stack overflow occurs, the memory is full. The computer has no where to put new instructions, so it crashes.

Now that we understand how dynamic variables can be dangerous, we can learn to use them properly.

Pointers

A pointer is special kind of data type. Unlike primitive data types, which store things like ASCII characters, integers, and floating-­point numbers, a pointer stores a memory address. We call them pointers because they act like road signs that point to a destination.

To declare a pointer, we type the primitive data type of our destination variable followed by an asterisk. The primitive data type plus the asterisk form the pointer data type. The pointer variable will be used for storing memory addresses of variables that correspond with the pointer’s primitive type.

// A variable for storing the address of a char variable.
char * char_pointer;

// A variable for storing the address of an int variable.
int * int_pointer;

// A variable for storing the address of a double variable.
double * double_pointer;

When a pointer is first declared, it doesn’t contain a memory address. A good practice for initializing pointers is assigning them to NULL.

// Initializing pointers to point to no address.
char * char_pointer = NULL;
int * int_pointer = NULL;
double * double_pointer = NULL;

A pointer can be used to indirectly change the contents of some variable. Here’s an example. Suppose we want to change the char variable, grade, from ‘F’ to ‘A’ without touching the grade variable itself. We can do this as long as we have the address of grade. We can return the address of a variable by putting an ampersand in front of it. We can save this address in a pointer variable. Let’s name this pointer something obvious, like grade_pointer.

// Create a char variable and a char pointer.
char grade = 'F';
char * grade_pointer = NULL;
cout << grade << endl; // F
    
// Assign the address of grade to grade_pointer.
grade_pointer = &grade;
    
// Indirectly change the contents of grade.
*grade_pointer = 'A';
cout << grade << endl; // A

Now we can view the contents of grade indirectly by using our grade_pointer. We can also change the contents of grade with our grade_pointer. To access or make changes to the value in grade, we put an asterisk (*) in front of grade_pointer.

Arrays and Pointers

An array is a homogeneous and contiguous block of memory. By homogeneous, I mean that all elements of the array are the same data type. By contiguous, I mean that the elements are physically located right next to each other in memory.

If we return the address of an array, we will get the address of the first element. We can traverse an array by using a pointer. Suppose we assign a p to hold the address of a char array. We can traverse through the array by incrementing the pointer.

// Create an array of int values.
int array[5] = {12, 45, 890, -12, 5};
    
// Store the memory address of the array in p.
int * p = array;
    
// Traverse through the array via pointer.
for (int i = 0; i < 5; i++)
{
  // Access the contents of the memory address in by p.
  cout << *p << endl;
        
  // Increment the pointer by one int size.
  p++;
}

Dynamic Arrays

We can create dynamic arrays using pointers. The following code accepts an array size from console input during runtime. Then it creates an array of that size. We use the keyword, new, when we create a dynamic variable. When we are done using the dynamic array, we have to deallocate its memory using the delete operator.

// Get the array size from console input.
int array_size = 0;
cout << "Enter an array size: " << flush;
cin >> array_size;
    
// Create the array dynamically.
int * dynamic_array = new int[array_size];
    
/** Do things with the array */
    
// At the end of the program, deallocate array memory.
delete [] dynamic_array;

Conclusion

Hopefully now, you have a basic understanding of how pointers and memory works. This is important to know if you want to understand how computers work internally.

References


Categories: sciencetechnologytutorials