Pointers are not integer types, even though computers typically handle addresses as integers. Conceptually, pointers are distinct types from integers. Integers are numbers you can add, subtract, divide, and so on. But a pointer describes a location, and it doesn’t make sense, for example, to multiply two locations by each other. In terms of the operations you can perform with them, pointers and integers are different from each other. Consequently, you can’t simply assign an integer to a pointer:
int * pt;
pt = 0xB8000000; // type mismatch
Here, the left side is a pointer to int, so you can assign it an address, but the right side is just an integer. You might know that 0xB8000000 is the combined segment-offset address of video memory on your aging computer system, but nothing in the statement tells the program that this number is an address. C prior to C99 lets you make assignments like this. But C++ more stringently enforces type agreement, and the compiler will give you an error message saying you have a type mismatch. If you want to use a numeric value as an address, you should use a type cast to convert the number to the appropriate address type:
int * pt;
pt = (int *) 0xB8000000; // types now match
Now both sides of the assignment statement represent addresses of integers, so the assignment is valid. Note that just because it is the address of a type int value doesn’t mean that pt itself is type int. For example, one might have a platform for which type int is a 2-byte value and the addresses are 4-byte values.
Pointers have some other interesting properties that we’ll discuss as they become relevant. Meanwhile, let’s look at how pointers can be used to manage runtime allocation of memory space.
Allocating Memory with new
Now that you have a feel for how pointers work, let’s see how they can implement the important technique of allocating memory as a program runs. So far, you’ve initialized pointers to the addresses of variables; the variables are
Let’s try out this new technique by creating unnamed runtime storage for a type int value and accessing the value with a pointer. The key is the C++ new operator. You tell new for what data type you want memory; new finds a block of the correct size and returns the address of the block. You assign this address to a pointer, and you’re in business. Here’s an example of the technique:
int * pn = new int;
The new int part tells the program you want some new storage suitable for holding an int. The new operator uses the type to figure out how many bytes are needed. Then it finds the memory and returns the address. Next, you assign the address to pn, which is declared to be of type pointer-to-int. Now pn is the address and *pn is the value stored there. Compare this with assigning the address of a variable to a pointer:
int higgens;
int * pt = &higgens
In both cases (pn and pt), you assign the address of an int to a pointer. In the second case, you can also access the int by name: higgens. In the first case, your only access is via the pointer. That raises a question: Because the memory to which pn points lacks a name, what do you call it? We say that pn points to a
The general form for obtaining and assigning memory for a single data object, which can be a structure as well as a fundamental type, is this:
You use the data type twice: once to specify the kind of memory requested and once to declare a suitable pointer. Of course, if you’ve already declared a pointer of the correct type, you can use it rather than declare a new one. Listing 4.17 illustrates using new with two different types.
Listing 4.17. use_new.cpp
// use_new.cpp -- using the new operator
#include
int main()
{
using namespace std;
int nights = 1001;
int * pt = new int; // allocate space for an int
*pt = 1001; // store a value there
cout << "nights value = ";
cout << nights << ": location " << &nights << endl;
cout << "int ";