Pointers

Part 1: Basics

·

9 min read

Pointers

Pointers have been one topic that I struggled with a lot during my first year and part of my second year of college. It wasn’t that I didn’t know what they were or how to implement, I would say it was more of the fact that I failed to grasp the content of having to manage them on my own that was the hard thing.

I mean, why do I have to write code dealing with memory addresses when all I wanted was to just write code and let the compiler handle all the memory on itself without me knowing what was going on in the back. Then, I encountered linked lists which practically need pointers in order for them to be implemented and that sparked the idea to go back and re-learn pointers and this time I started liking them and actually understood them.

In this article, I explain what pointers are, how you can use them and how I managed to finally understand them.

Table of Contents

1. What are pointers

2. Advantages & Disadvantages of Pointers

3. Declaring Pointers

4. The address of operator

5. The indirection or dereferencing operator

6. Operations allowed on pointers

7. Comparing pointers

What are pointers?

C++ offers you 3 classifications of data types; simple, structured and pointer data types. Pointers are a tricky topic to deal with. This is because you, as the programmer, has to learn how to properly manage them in your programs otherwise you risk creating a program that does not properly utilise computer memory. This is unlike when dealing with Java because Java manages the pointers on your behalf and you do not have to worry about them.

Memory is something that is very vital, this is because whatever program you write will officially have to be loaded into memory at runtime. Pointers, sometimes called pointer variables are integers whose content are memory addresses in the computer and help you to manage memory. They are very important when dealing with and implementing with dynamic arrays and linked lists. Since pointer’s contents are addresses, it can be said that a pointer points to a particular location in memory and it allows you to work with the data contained in that particular memory address.

Pointers almost work the same way that reference variables do, however, they allow you to work with data at a lower level as compared to reference variables. This means that C++ does not do much of the work for you as compared to how it handles reference variables.

Computer memory addresses are usually represented using a hexadecimal value that starts with 0x with other numbers. You will see a lot of this number as you learn pointers so do not confuse it for when the complier prints out garbage.

Advantages & Disadvantages of Pointers

Before I jump into how you can write code for pointers, it is important that you understand it’s advantages as well as disadvantages as this will help know whether your program needs pointers or not.

Advantages:

• Used for dynamic memory allocation

• Useful in algorithms that manipulate arrays and work with certain types of strings

Disadvantages:

• Hard to manage and/or maintain

• Careful consideration has to be put when dealing with pointers so that data is not stored in the pointer itself but pointed to by the pointer.

Declaring Pointers

Declaring pointers is done the same way that you would declare a simple variable; it starts with a data type followed by the name of the variable. However, in order for that variable to be considered a pointer, a special symbol has to be placed between the data type and the variable name. The special symbol is an asterisk (*) and is also known as the Dereferencing Operator or Indirection Operator depending on how you want to use it, it is essentially important when dealing directly with the data pointed to.

void * pointerAddress;

The above declaration declares the most basic of pointers of type void and it can be said that it is a void pointer. pointerAddress points to memory location of type void hence it cannot be made to point to another memory address of another data type.

Pointers can be declared however you most feel comfortable, below are some ways in which we can declare the pointer above;

void* pointerAddress; // way two
void *pointerAddress; // way three

Whichever method you decide to go with is entirely up to you and your preference but make sure that you are consistent with your chosen style as this will prevent you and others that may read your code from misinterpreting what you initially meant.

NOTE: the following syntax does not mean what you think it does,

string *pointerAddress, pointed;

The above code declares two variables of type string and makes pointerAddress a pointer while the pointed variable is just a simple variable. This is not the same as writing

string *pointerAddress, *pointed; // declares two pointer variables of type string

This then implies that both pointerAddress and pointed variables are pointers of type string.

The Address of Operator

The address off operator also known as an ampersand (&) is a unary operator, meaning that it only deals with one operand.

Let us take this example on how we use this operator; suppose we have a variable number of type int and a pointer called numPointer of type int as well. Let’s assign number to 200 and then assign the address of number to numPointer and the we can display the address that numPointer now points to.

int number = 200; // int variable to store our value
int *numPointer = &number; // assigning the address of number to numPointer
std::cout << numPointer << endl;

By placing the address of operator (&) in front of our variable number, what we are essentially doing is telling the complier that we want it to now point to the address where number is stored.

Whenever we want to print out the particular address of a variable without using a pointer, you can do this by simply placing the address of operator in front of the variable name in your cout statement.

int number = 200;
std::cout << “The address of number is: " << &number << endl;

As you have seen, when we are dealing with pointers, in your cout statement you do not have to prefix the pointer name with the address of operator as the complier explicitly now knows that you are dealing with pointers especially when you have declared the pointer correctly. This however starts to get confusing when you are working multiple variables and you are writing many lines of code. You can only follow along when dealing with short programs.

The Indirection or Dereferencing Operator We have seen how we declare pointers using the dereferencing operator (*) and assign memory address to them, we have also seen how we can use print that address to the console without using pointers.

Here, we will at how you can use pointers to manipulate and modify the data stored in the address pointed to by the pointer. We can use the same operator we used earlier to define a pointer to modify the contents. This is done by placing an asterisk before the pointer name and then reassigning our variable to something.

However, this can only be done after our variable and pointer have been declared and the address of the variable has been assigned to the pointer.

Using the example above, we can then modify the value in number and reassign it to 100 instead using the pointer numPointer and then we display the new value that it now points too.

int number = 200;
int *numPointer = &number;
*numPointer = 100;
std::cout << *(numPointer) << endl;

By placing the indirection operator before the name of the pointer, what we are essentially doing is telling the compiler that we want it to dereference the pointer so we can work with the data whose address it points to.

And in order for us to view the new modified value, we place an asterisk before the opening brace and then writing the name of the pointer and closing the brace as seen in the code above.

Operations Allowed on Pointers

Be careful when you are working with pointers as they do not work the same way that simple variables do. Certain operations are permitted on pointers and some are not.

You cannot divide or multiply pointer variables as this will lead to you getting wrong results or your code not compiling at all. However, you can perform addition and subtraction on pointer variables as well as incrementing and decrementing pointer variables.

When you increment a pointer variable, you are not adding a one (1) the same way that happens with simple variables. With pointers, it actually increments by the number equal to the size of the data type for which it is a pointer.

Given a pointer of type int and knowing full well that an int has four bytes and its memory address is 1000, when we increment the pointer, what we are actually doing is adding four more bytes and hence the new address would be 1004 and not 1001.

The same is also true for when decrementing a pointer.

Using the example above, we can illustrate this in code.

int number = 200;
int *numPointer = &number;
*numPointer = 100;
std::cout << “The address of number before incrementing: " << numPointer << endl;
numPointer++;
std::cout << “The address of number after incrementing: " << numPointer << endl;

std::cout << “The address of number before decrementing: " << numPointer << endl;
numPointer--;
std::cout << “The address of number after decrementing: " << numPointer << endl;

When a pointer is added or subtracted from a value, the value is first multiplied by the size of the data type and then added or subtracted from the pointer. This ensures that we are still dealing with memory addresses at the end of it all and not the actual value the pointer points to.

Comparing Pointers

If one address comes before another, the first address is then considered as being less than the second one. 1000 less than 1008 and this hold for pointers as well.

You can use relational operators to compare two or more pointers the same way that you compare simple variables and using the same operators (==, !=, >, >=, <, <=) when either dealing with the actual memory addresses or when dealing with the values pointed to.

Summary

Pointers are the basis for any program that you want to write that will use memory allocation, dynamic arrays and linked lists and many more other types of programs. Having a good grasp on how to use them will save you from making a mistake that will cost you computer memory and making errors that would have otherwise been avoided.

This was how I was able to learn Pointers and hopefully you found this helpful in some way.

Connect with me on:

Twitter

LinkedIn

GitHub