SDAP :: Introducing Pointers
In our previous lesson, we learned about int or integer data types, variables and constants.
In this lesson we're going to learn about another, slightly more complicated data type. It's called a pointer.
Memory, CPU and Programs
First, a short lesson about memory. As you probably already know, computers have memory. You might hear this referred to as RAM or Random Access Memory.
The CPU or Central Processing Unit is the component that processes your programs and data.
Before the CPU can process anything, it must first be loaded into memory. Not only are the programs located in memory, but the variables are located in memory as well.
In order for the CPU to access memory, the CPU must be able to have a way to specify exactly where in memory something is located. That is called the address of the memory location.
In short, a pointer is a variable that contains an address. In C++, a pointer also has a type associated with it. This lets the compiler know what type of variable or value the pointer is addressing.
Declaring a Pointer Type
In the last lesson we learned about int types. In this lesson we'll learn about int pointer types, which is a pointer to a int value.
To declare a pointer, you modify the type with an * or asterisk. For instance, to declare an int pointer you would write something like this:
int* pointer;
Initializing a Pointer
In the previous lesson we learned to initialize an int type like this:
int value(1);
value in this case is an integer that is initialized to 1.
To initialize a pointer, we need to use a special operator called the address operator which is the & or ampersand symbol.
The following example initializes the variable pointer to the address of the variable value.
// Declare the int variable value and initialize it to 1 int value(1); // Declare the int pointer variable and initialize it to the address of value. int* pointer(&value);
So, to break it down a little, the int* pointer portion declares an integer pointer named pointer. The (&value) portion initializes the variable pointer to the address of the variable value.
To make it a little easier to understand, lets see the example in a less correct format:
// Declare the int variable value and initialize it to 1 int value(1); // Declare the int pointer int* pointer; // Assign the pointer variable to the address of the value variable. pointer = &value;
In this example, we declared the int pointer first, then we assigned a value to it by getting the address of the value variable.
De-referencing
We've learned how to take a variable and get the address of it and store it into a pointer variable. The original variable directly references a value and a pointer indirectly references a value.
To get the address, we use the address of operator, which is the & or ampersand.
To go the other direction where we take the address stored by a pointer and get the value is called dereferencing. To do this you use the dereference symbol which is the * or asterisk symbol.
Lets take the previous example and extend it.
// Declare the int variable value and initialize it to 1 int value(1); // Declare the int pointer int* pointer; // Assign the pointer variable to the address of the value variable. pointer = &value; // Declare another int variable named anotherValue int anotherValue; // Assign a value to anotherValue by dereferencing the pointer. anotherValue = *pointer;
Here we create a new int variable and assign it the value located at the address pointed to by the pointer variable.
Since pointer is pointing to value and value has the value of 1, anotherValue also has the value of 1.
Confusion
Now lets confuse things a bit. First, I'm going to start using proper programming and naming conventions.
// Declare the int variable value and initialize it to 1 int myValue(1); // Declare the int pointer int* pPointerToValue(&myValue); // Declare another int variable and initialize it to 0. int anotherValue(0); myValue = 2; anotherValue = *pPointerToValue; myValue = 3; int yetAnotherValue(*pPointerToValue);
First, myValue is initialized to the value of 1. pPointerToValue is initialized to the address of myValue. anotherValue is initialized to a value of 0.
Next, we change the value of myValue to 2. pPointerToValue still contains the address of myValue.
So, in the following line, anotherValue is assigned a value by dereferencing pPointerToValue.
At that point in time, since pPointerToValue contains the address of myValue and myValue has the value of 2, anotherValue is assigned the value of 2.
The following line of code changes the value of myValue. But, it does not change the value of anything else. pPointerToValue still contains the address of myValue and we didn't modify anotherValue.
This is because when we assigned anotherValue, that assignment took place immediately and subsequent changes to myValue or pPointerToValue will not effect anotherValue.
The following line we create another variable named yetAnotherValue and assign it by dereferencing pPointerToValue. Since pPointerToValue still points to myValue and myValue now has the value of 3, yetAnotherValue has the value of 3. After these lines of code are executed, the variables have these values:
| myValue | 3 |
| pPointerToValue | address of myValue |
| anotherValue | 2 |
| yetAnotherValue | 3 |
Exercise 1
Edit your FirstProgram application and make it look something like this.
int main(int _argc, char* _argv[]) { // Initialize three variables int value1(0); int value2(0); int value3(0); // Declare a pointer int* pointer1; pointer1 = &value1; pointer1 = &value2; pointer1 = &value3; value1 = 1; value2 = 2; value3 = 3; // Get the value of the pointer by dereferencing it. int returnValue(*pointer1); // Return it return returnValue; }
What will the value of returnValue be when the program returns?
Compile the program, then step through it with the debugger. Make sure you set a breakpoint on the line return returnValue.
When you get to that point, hover over the variable name returnValue so it will tell you the value. Did you get it right?
Also, notice when you hover over a pointer, there's a little + or plus symbol next to it. If you click on that symbol, the little window will expand and you will be able to see the value that the pointer is addressing.
If you didn't get the answer right and you don't understand, please ask questions in the forums or on IRC. irc://208.109.123.232:16667/indiezen
Constant Pointers and Pointers to Constants
Ok, so we understand pointers now hopefully.
Next, lets talk about constant pointers and pointers to constants
In the previous C++ lesson we learned about constant variables using the keyword const.
In this example, myValue is a constant integer that has (and always will have) a value of 10.
const int myValue(10);
Extending this example, lets add a pointer to the variable.
const int myValue(10); const int* pPointerToMyValue(&myValue);
There, that was easy... pPointerToMyValue points to a constant integer and is initialized to the address of myValue.
Now, note that pPointerToMyValue is not itself constant. It only points to a constant value.
In the following example, we declare and initialize another variable named anotherValue then we modify pPointerToMyValue so that it has the value of the address of anotherValue.
const int myValue(10); const int* pPointerToMyValue(&myValue); const int anotherValue(14); pPointerToMyValue = &anotherValue;
This is legal because pPointerToMyValue is not constant. The value that is pointed to by pPointerToMyValue is constant, but the pointer itself is not constant.
To make a pointer constant, you have to move the location of the keyword const.
In this example we show myValue being initialized to 10. Notice that myValue is not constant.
In the following line, we declare pPointerToMyValue which is a constant pointer to an int. This means that the pointer itself cannot change, however the value which it points to can change.
In the third line of this example we show just that. myValue is modified to have the value 14. This is legal because myValue is not constant.
int myValue(10); int* const pPointerToMyValue(&myValue); myValue = 14;
If we were to change the program to look like this:
int myValue(10); int* const pPointerToMyValue(&myValue); myValue = 14; int anotherValue(13); pPointerToMyValue = &anotherValue; /// WRONG! pPointerToMyValue is const
... you would get a compile error.
The following example would also cause a compile error.
const int myValue(10); const int* pPointerToMyValue(&myValue); const int anotherValue(14); pPointerToMyValue = &anotherValue; /// Legal, pPointerToMyValue is not const myValue = 12; /// WRONG! myValue is const
Now, we can also combine these two const modifiers.
In the following example, pPointerToMyValue is a constant pointer that points to a constant value.
const int myValue(10); const int* const pPointerToMyValue(&myValue); const int anotherValue(14); pPointerToMyValue = &anotherValue; /// WRONG! pPointerToMyValue is const myValue = 12; /// WRONG! myValue is const
More Exercise
If you would like more text explaining pointers, feel free to read HTPCPP Chapter 8.2. If you're an experienced programmer, please feel free to read all of Chapter 8 if you're interested.
Edit your FirstProgram and play around with int and int * data types and variables. Be sure to use the debugger to see if the program behaves as you expected.
Play around with the const and non-const variables and see if you can predict when you will get compiler errors due to assigning values to a constant variable.
If you have any questions, please be sure to ask them in IRC or in the forums.
