This chapter relies extensively on terminology introduced in earlier chapters. Please review these terms as needed:
Pointers are surprisingly powerful and, therefore, immensely useful. Most aspects of programming use pointers in one way or another. Even languages like Java that have ostensibly eliminated pointers rely heavily on them. The interdependence of pointers with other programming features makes choosing the best presentation sequence difficult. Most of the programming features presented in subsequent chapters rely, at least in part, on pointers, suggesting their early presentation. Yet, without the context of those features, pointers have little utility, detaching them from practical programming and making authentic examples difficult to find. So, the text introduces pointers first, with minimal forward references. It relies on your previous experience with Java or Python to provide the necessary background, revisiting the advanced programming features in upcoming chapters where it adds detail, context, and examples.
Our first and most significant challenge is understanding pointers at a fundamental level. So, we begin with an analogy based on a more familiar feature: shortcuts (Windows) or symbolic links (Unix/Linux/macOS). A file is a collection of related information with a human-readable name. Operating systems maintain the file's contents on secondary storage (e.g., disk or flash drives) and its name in a directory or folder. They display the file's information with different system programs (e.g., Windows Explorer, dir, tree, ls, etc.). An absolute pathname uniquely denotes the file's location within the file system.
Once we create a file, shortcuts allow us to have additional names for the original file. Three variations of the additional names provide convenience and flexibility:
(a) | (b) |
In this example, the file is an executable program. It's a common practice to put shortcuts for frequently used programs on the desktop. If I launch the Spotify program by double-clicking the shortcut in the Desktop directory. The computer first opens and reads the shortcut file and then opens and runs the Spotify executable file named in the shortcut file. Shortcuts require the operating system to open and read an additional file, slowing the program's startup. But shortcuts are typically much smaller than a program file. So, on balance, the slight startup overhead allows me to have one program file and as many shortcuts as I want, wherever convenient.
As we study pointers, we must include two concepts not formally introduced until later chapters: arrays and classes. We'll use these topics without much detail, revisiting arrays in Chapter 7 and classes in Chapter 9. Until then, we'll rely on your experience from last semester. At the conceptual level, C++ and Java are very similar. For those of you who are beginning C++ without the benefit of CS 1400 or previous Java experience, the review section in Chapter 1 will fill in some of the needed detail and the remaining forward references are brief and undetailed.
We begin our discussion of pointers by exploring a simple statement in Java. Suppose that a Java program declares a class named Person and that it has two instance fields named name and id, respectively. In that case, we can illustrate the statement and its impact on memory with the following illustration. Java textbook authors often claim that Java does not have pointers, which is technically correct - Java has references; however, the distinction between a pointer and a reference is very subtle. The key to understanding the following figure is that variable p points to the Person object, wherever it is in memory. The same picture can also apply to a similar operation in C++.
Person p = new Person(); |
|
(a) | (b) |
---|
Person p
, does not create an instance of class Person - it defines a variable that can hold the address of a Person object; the right side of the assignment operator, new Person()
, instantiates an object and returns the address of that object.We can create objects in a C++ program the same way we do in a Java program. So, the (b) parts of Figures 2 and 3 are identical, and the (a) parts are very similar. The challenge is that C++ can create objects in multiple ways, whereas Java, ignoring a couple of exceptional cases, can create them in only one way. C++'s increased flexibility requires additional syntax and a deeper understanding of memory management to appreciate which method is best in a given situation. Figure 3 illustrates the syntactic options and the associated abstract representations associated with C++.
Person* p = new Person; |
|
(a) | (b) |
---|---|
Person p; |
|
(c) | (d) |
Person* p
defines a pointer variable; new Person;
creates a Person object and returns its address, which the assignment operator stores in the pointer variable. (Notice that parentheses before the terminating semicolon are optional.)Person p;
creates a new Person object, but the variable p directly names the object. Late in the chapter, we'll learn that the object's name, p, represents its address.All of the above suggests that while pointers and their associated syntax can be conceptually challenging to understand, learning how to use them to solve problems is well worth the time and effort it may take. Pointers are a kind of variable that allows programmers to work with memory addresses, so we begin by exploring the relationship between variables and addresses.