References
A reference is essentially an alias. It points to the same memory address as the variable, and changes to one affect the other. References are assigned using the ampersand ‘&’ symbol. In the example below, changes to origVar affect newVar, and vice versa:
int main() { int origVar = 10; int& newVar = origVar; origVar *= 2; cout << "origVar/newVar: " << origVar << "/" << newVar << endl; // outputs 20 newVar *= 2; cout << "origVar/newVar: " << origVar << "/" << newVar << endl; // outputs 40 }
References must be initialized at declaration, rather than split over multiple statements. For instance the following gives a `newVar’ declared as reference but not initialized error:
int& newVar; newVar = origVar; // results in compile error
And the following simply fails, without a compile error – newVar will not be assigned to origVar:
int newVar; newVar &= origVar; // fails to assign the reference, without an error message
References cannot be reassigned. In the example above, adding two new lines at the end:
... int tempVar = 100; int& newVar = tempVar;
Will result in a redeclaration of `int&newVar’ error.
Pointers
Pointers are another way to refer to the value of a variable, however unlike References, pointers refer to the memory address itself. Pointers are assigned using the asterisk (*) symbol. In assignment, the ‘*’ is used with the ‘&’ operator – which when before a variable name is not for a reference, but rather the address-of operator (except with arrays, which do not need an ‘&’ as they already store a memory address).
After a pointer is assigned, use the ‘*’ again as the Dereference operator. This will tell the compiler to retrieve the value at the pointer’s memory address.
Pointers are more powerful than references. A pointer does not need to be initialized (though if it is not initialized you should always set its value to zero, ‘0’), and also unlike references pointers can be reassigned. You can also have multiple levels of indirection, with pointers pointing to pointers.
When declaring pointers, you can declare multiple pointers per line, but each must be preceded with ‘*’. Example:
int * A, * B; // both A and B are pointers, type int* int * C, D // C is a pointer, type int*, but D is a regular int
Pointer Precedence
Be careful when using pointers with other operators. The increment/decrement operators take precedence over the dereference operator. Below, in this first example, junk is outputted:
int number = 100; int * pointer = &number; *pointer++; // changes the memory address of the pointer! cout << *pointer << endl; // outputs junk cout << number << endl; // number remains 100
What we want is this second example:
int number = 100; int * pointer = &number; (*pointer)++; // changes the value cout << *pointer << endl; // outputs 101 cout << number << endl; // number is also changed to 101
The first example is incorrect, because it is the same as *(pointer++), since the increment takes place first. Thus, *pointer++ actually refers to the *memory address* being incremented. What we want is (*pointer)++, which increments the value of the pointer, and thus changes number as well.
A pointer example:
int main() { int var1 = 100; int var2 = var1; // becomes 100 int * var3 = &var1; // becomes some memory address int var4 = *var3; // becomes 100 cout << var1 << ":" << var2 << ":" << var3 << ":" << var4 << endl; }
This will output something like 100:100:0xbfffae14:100. Note that these variables are independent, except var3 which points to var1. Changing one after the above code will not affect the values of the others, unlike with references. However if you do var1=200 prior to int var4 = *var3, then var4 will be assigned the value ‘200’, because var3 always points to the address of var1, and *var3 always refers to the value of var1.
Pointer reassignment example:
int main() { int firstVal, secondVal; int * pointer; pointer = &firstVal; // pointer is a memory address *pointer = 100; // *pointer and firstVal are now 100 pointer = &secondVal; // pointer reassigned to a different memory address *pointer = 200; // *pointer and secondVal are now 200, firstVal is still 100 cout << "firstVal: " << firstVal << endl; cout << "secondVal: " << secondVal << endl; }
This is an example of a pointer being reassigned. Since pointer points to the memory address of firstVal, changing *pointer changes firstVal, and likewise with secondVal. But the reassignment disassociates pointer with firstVal.