The Rise and Fall of Pointer Arithmetic in the Evolution of Memory Management
Introduction
Have you ever watched a movie where a car drives off the edge of a cliff? Listing 1 shows what would happen if you implemented this scenario in code.
Listing 1Accessing memory past the array bounds.
// Pointers01.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <iostream> using namespace std; int myArray [] = {2, 15, 24, 36, 48}; int main () { int i=0; for (i=0 ; ; i++ ) { printf("myArray[%d]= %d\n", i, myArray[i]); } return 0; }
When this program is executed, it actually crashes (an appropriate metaphor), as shown in Figure 1.
Figure 1 C++ runtime message.
The reason that this C++ application "falls over the cliff" has to do with the fact that the for loop literally blows past the edge of the array and, very inelegantly, tramples on memory that doesn't belong to it. The possibility of code "trampling" on inappropriate memory occurs because C++ allows the use of pointer arithmetic—which means, among others things, that a programmer can directly access and manipulate memory addresses.
As Figure 2 shows, the application literally made it as far as myArray[4095] before the runtime even bothered to notice. And when the runtime finally paid attention—it wasn't happy.
Figure 2 Working through restricted memory.
Interestingly, many programmers who began their careers after the year 2000 have never used a development environment that would even allow code like this. Programmers who develop primarily with modern object-oriented development environments don't have pointer arithmetic like this in their toolkit. Java, .NET, C#, Visual Basic, and so on simply don't allow direct manipulation of memory locations.