21.8. Valid Pointer Operations

[ fromfile: memoryaccess.xml id: pointerops ]

Following is a list of the operations that can properly be performed with pointers.

Creation – The initial value of a pointer has three possible sources:

Assignment

Arithmetic

Comparison

Indirection

If p is a pointer of type T*, then *p is a variable of type T and can be used on the left side of an assignment.

Indexing:

A pointer p can be used with an array index operator p[i] where i is an int. The compiler interprets such an expression as *(p+i). Indexing makes sense and is defined only in the context of an array, but the compiler will not prevent its use with nonarray pointers where the results are undefined.

Example 21.7 demonstrates this last point rather clearly.

Example 21.7. src/arrays/pointerIndex.cpp

#include <iostream>
using namespace std;

int main()  {
    int x = 23;
    int y = 45;
    int* px = &x;
    cout << "px[0] = " << px[0] << endl;
    cout << "px[1] = " << px[1] << endl;
    cout << "px[2] = " << px[2] << endl;      
    cout << "px[-1] = " << px[-1] << endl;
    return 0;
}
Output:

// g++ on Mac OSX:
px[0] = 23
px[1] = 1606413624
px[2] = 32767
px[-1] = 45

// g++ on Linux (Ubuntu):
px[0] = 23
px[1] = -1219095387
px[2] = -1216405456
px[-1] = 45

// g++ on Windows XP (mingw)
px[0] = 23
px[1] = 45
px[2] = 2293588
px[-1] = 2009291924

// Windows XP with MS Visual Studio compiler:
px[0] = 23
px[1] = 45
px[2] = 1245112
px[-1] = 1245024



<include src="src/arrays/pointerIndex.cpp" href="src/arrays/pointerIndex.cpp" id="pointerindexcpp" mode="cpp"/>


Here we have a small, concrete example of what we mean when we talk about undefined behavior. A beginner might be forgiven for making some assumptions about how consecutively defined variables are arranged on the program stack. Using array subscripts on a nonarray pointer or using subscripts that are beyond the range of the array are just naughty ways of exploring that imagined landscape, right? Well, now try to fit the subscript -1 into that intuitive map. Then try to reconcile the different results on the different platforms. This example is too short to show the complete picture, however. Undefined behavior of pointers generally leads to corrupted memory – and corrupted memory is a programming nightmare – with runtime abort as one of the more desirable outcomes.