Introduction

This is the first in a tutorial series on C and C++ pointers. It is written for beginning programmers to clarify pointer concepts, but is a great refresher for all programmers. It includes concrete code snippets, diagrams, and discussion text. For a more advanced, under-the-hood deep dive on arrays, pointers, and references, see this post. Let’s dive right in.

What are Pointers in C and C++?

Pointers in C and C++ are variables that point to other variables. They can also point to unnamed places in computer memory.

Foundations: What is a Variable?

A variable is an object that takes up space in computer memory, and that has a name and a type. We can assign a value to the variable, which is stored in the “cubby hole,” or memory space, reserved for it.

char Variables

char c;  // Define a variable whose name is c, type is char
c = 'g'; // assign the character 'g' to variable c
         // placing a 'g' in c's memory "storage area"

printf("%c", c); // Print out: g

In the above variable definition, c is the name of the variable, and char is the type. The type of a variable defines both the size of the variable in memory (for char variables, one byte, the smallest addressable area in memory) and how it is to be handled by the compiler (it can be assigned a letter like 'g' or a signed integer whose values can go from -128 to 127):

int Variables

int i;     // Define a variable whose name is i, type is int
i = 15339; // assign the integer value 15339 to i

printf("%d", i); // Print out: 15339

Above, we have defined a variable named i of type int. It is an object that takes up four bytes in memory, and is treated by the compiler as a signed integer variable whose values can go from -32768 to 32767.

Note that the variable names are arbitrary, as long as they are in the proper format and do not collide with other names, such as keywords or names in libraries or other linked in code.

Variables in Memory

When the program is run, the compiler/system will place each of these variables at a certain location in memory associated with an address. For instance, if we have 16 bytes of memory, with the first byte starting at address zero and the last byte starting at address 15 (zero to 15 inclusive is 16), the compiler/system could place c at address two (the third byte from the bottom), and i at address four (the fifth byte from the bottom):

char and int in Memory Diagram
char and int in Memory

Pointers Explained

A pointer is exactly what its name implies: a pointer to something. A pointer is a variable, just like a char or int variable, but its type is pointer to type, where you specify the type:

Defining Pointers

char *pc; // Defines a variable named pc of type "pointer to char"
int *pi;  // Defines a variable named pi of type "pointer to int"

Above, the * operator after the type (char and int) is what indicates to the compiler you are defining a pointer to that type. The type of pc is pointer to char, and the type of pi is pointer to int.

Assigning Values to Pointers

Since pointers are variables, like char and int, you must assign them a value, and the value you put in them is the address of the variable you want the pointer to point to (you can also assign them the value nullptr, which indicates they point to nothing):

char c;   // Define a char variable
int i;    // Define an integer variable

char *pc; // Defines a variable of type "pointer to char"
int *pi;  // Defines a variable of type "pointer to int"

pc = &c;  // Get the address of the char variable c and put it in pc
pi = &i;  // Get the address of the int variable i and put it in pi

printf("%p %p", pc, pi); // Print out: 00EFFB0B 00EFFAFC

Above, the & address of operator takes the address of a variable, so &c returns the address of the variable c, and here we assign it as the value for the pointer pc. Since the address of c is 2, that is what gets put into pc. Similarly, the value 4 gets put in pi:

Pointers to char and int Diagram
Pointers to char and int

You can see above clearly that the value assigned to the pointer (the number put into the pointer) is the address of the variable it points to.

Pointers are Just Variables in Memory Too

Pointers are variables. In the diagram above, I put them to the side to make it easier to see the point being made: that they point to a variable and that the value stored in the pointer variable is the memory address of the variable they point to. However, Pointers are variable objects just like any other variable, so they also reside in computer memory:

char, int, and pointers in Memory Diagram
char, int, and Pointers in Memory

As you can see, I have changed the figure to have the pointers placed in memory like any other variable, and the compiler/system has placed them at their very own respective addresses. Note that for a 16 byte total memory system, a single byte is sufficient to hold all the possible addresses, so that is how I did it in the above diagram to save space.

In a typical desktop or server system, the program would running in either a 32 bit (4 byte - for instance x86) environment, so the size of the pointer would need to be 4 bytes (the same size as an int), or a 64 bit environment (8 bytes - for instance x64), so the size would need to be 8 bytes.

Using Pointers

Once one has pointed a pointer to another variable, one uses the * prefix operator to retrieve the value that is inside the variable that the pointer points to. This is called dereferencing (a pointer refers to another variable, so de-reference-ing is to change it from a reference to the variable to the actual value of the variable it references, just as if one directly used the referenced variable itself):

  char c = 'g';  // define char variable c and give it a value: 'g'
  char* pc = &c; // define pointer to char variable pc and give it the value: address of c

  printf("%c %p %c", c, pc, *pc); // prints out: g 00EFFB0B g

Note, above I have used the shortcut notation that assigns an initial value right in the definitions of each variable. First, I define a char variable named c, simultaneously assigning it the value 'g'. Then, I define a pointer to char variable pc, simultaneously assigning it the address of the variable c.

Finally, I print out to the console the value of c, directly using the variable c itself, the contents of the pointer to char variable pc directly, which is the four byte address (in hexadecimal notation) of the variable c, then the value of c again, this time using the * prefix operator to dereference pc, which returns the value of c, the variable to which pc points.

Changing Pointers

Pointers can be changed at any time to point to something else, and you can assign the contents of one pointer to another:

char c = 'g';   // Define char variable c and assign 'g' to it
char d = 'f';   // Define char variable c and assign 'f' to it

char *pc = &c;  // Define pointer-to-char variable pc and assign address of c to it
char *pd = &d;  // Define pointer-to-char variable pd and assign address of d to it

printf("%c %c %p %p %c %c", c, d, pc, pd, *pc, *pd); // prints out: g f 00EFFB0B 00EFFAFF g f

pd = pc; // Assign value of pc (address of char variable c) to pd
printf("%p %p %c %c", pc, pd, *pc, *pd); // prints out: 00EFFB0B 00EFFB0B g g

pc = &d; // Assign directly address of char variable d to pc
printf("%p %p %c %c", pc, pd, *pc, *pd); // prints out: 00EFFAFF 00EFFB0B f g

After defining and assigning to the two char variables c and d, I define and assign the address of c to pc then the address of d to pd. The first printf shows what one would expect: c holds 'g', d holds 'f', pc holds the address of c, pd holds the address of d, dereferencing pc (*pc) returns the value of c, and dereferencing pd (*pd) returns the value of d.

Since pointers are just variables that hold values which happen to be pointers to other variables, I can assign the value (“contents of”) one to another, as long as they are the same type of pointers. I do this (pd = pc), then the following printf shows that pd now points to c, just like pc.

Finally, I can directly put the address of d in pc (pc = &d) without affecting pd: as the following printf shows, we have ended up switching what pc and pd point to: pc points to d and pd points to c.

Assigning Values Using Pointers

Finally, we show below how to change the value of the variable a pointer points to:

char c = 'g';  // Define char variable c and assign 'g' to it
char *pc = &c; // Define pointer-to-char variable pc and assign address of c to it

printf("%p %c", pc, c); // prints out: 00EFFB0B g

*pc = 'f'; // Assign 'f' to variable c using dereferenced pointer-to-char variable pc
           // Does not change value of variable pc, rather changes value of variable c to which it points
printf("%p %c", pc, c); // prints out: 00EFFB0B f

Just dereference (using * prefix operator) the pointer in the assignment, and the variable the pointer points to will be updated instead of the value in the pointer itself. Of course, the type of the value you are assigning must be the same type as the variable being pointed to, not an address: in this case, a char type, not a pointer to char (not char *) type. When we assign to a dereferenced pointer, the value in the pointer (the address of what it points to) remains unchanged - it is the value of the variable it points to that is changed.

Conclusion

I hope I have accomplished my goal of providing an approachable and insightful tutorial on C and C++ pointers. If you have any corrections or constructive comments, feel free to contact me via my contact form. Next up in the series is investigating the close relationship between arrays and pointers along with pointer arithmetic.

Thanks to Pexels for the free image