Pointers, arrays, arithmetic.
Arrays and pointers in C++ are very closely related. In C++ an array name is like a constant pointer: the block of memory where an array name points cannot be changed, but what is stored there can change.
The relationship is so close that you can use pointer operators with array names:
int nums[] = {2, 4, 6, 8}; cout << nums[0] << endl; // prints 2 cout << nums << endl; // prints address where the array storage begins cout << *nums << endl; // prints 2
And you can use array subscripting operations with pointers:
int *myPtr = &nums[0]; // myPtr points to first element of nums cout << *myPtr << endl; // prints 2 cout << myPtr[0] << endl; // prints 2 cout << myPtr[1] << endl; // prints 4 cout << myPtr[2] << endl; // prints 6
The following are equivalent:
int *myPtr = &nums[0]; // myPtr points to first element of nums int *myPtr = &*nums; // myPtr points to first element of nums int *myPtr = nums; // myPtr points to first element of nums
C++ lets you perform arithmetic on pointer variables; however, pointer arithmetic works differently from normal arithmetic! You can add/subtract integers to/from a pointer using the corresponding operators (+
, +=
, -
, -=
, ++
, –
), but when these operators are used with pointers, the math is performed in terms of the size of the pointed data type.
In other words, adding 1 to a pointer makes it point to the next block of memory corresponding to the size of the underlying type; subtracting 1 from a pointer makes it point to the previous block of memory corresponding to the size of the underlying type. This is really only meaningful when performed on an array.
/** Pointer arithmetic. */ #include <iostream> using namespace std; int main() { int v[] = {2, 4, 6, 8, 12}; int *vPtr = v; cout << *vPtr << endl; // prints 2 vPtr = vPtr + 3; // vPtr now points to address vPtr + 3*sizeof(int), // i.e., v[3] cout << *vPtr << endl; // prints v[3] vPtr--; // vPtr now points to address vPtr - 1*sizeof(int), // i.e., v[2] cout << *vPtr << endl; // prints v[2] cout << *(vPtr + 2) << endl; // prints v[4] return 0; }
Subtracting one pointer from another returns the number of elements between two addresses:
/** Subtracting pointers */ #include <iostream> using namespace std; int main() { int v[] = {2, 4, 6, 8, 12, 0}; int *vPtr = &v[0]; int *vPtr2 = &v[3]; cout << vPtr2 - vPtr << endl; // prints 3 return 0; }
A common technique used to visit every element in an array is to walk down an array with a pointer:
/** Walking down an array. */ #include <iostream> using namespace std; int main() { int v[] = {2, 4, 6, 8, 12}; int *vPtr = v; for (int i = 0; i < 5; i++) { cout << *vPtr << endl; vPtr++; } return 0; }
This is especially common with zero-terminated (i.e., NULL terminated) partially-filled arrays:
/** Walking down a null-terminated array. */ #include <iostream> using namespace std; int main() { int v[20] = {2, 4, 6, 8, 12}; int *vPtr = v; while (*vPtr != 0) { cout << *vPtr << endl; vPtr++; } return 0; }
The examples below assume:
int vals[] = {4, 7, 11}; int *valptr = vals;
Access technique | Example |
---|---|
arrayName[N] | vals[2] = 17; |
pointerName[N] | valptr[2] = 17; |
arrayName and subscript arithmetic | *(vals + 2) = 17; |
pointerName and subscript arithmetic | *(valptr + 2) = 17; |
Operation | Example |
---|---|
Increment pointer++ | valptr++; // points at 7 |
Decrement pointer-- | valptr--; // now points at 4 |
Arithmetic pointer + int and pointer - int | cout << *(valptr + 2); // prints 11 |
Compound assignment pointer += int and pointer -= int | valptr = vals; // points at 4 valptr += 2; // points at 11 |
Pointer subtraction pointer - pointer | cout << valptr - val; // # of ints between valptr and val |