Numerically, these two addresses are the same, but conceptually &tell[0], and hence tell, is the address of a 2-byte block of memory, whereas &tell is the address of a 20-byte block of memory. So the expression tell + 1 adds 2 to the address value, whereas &tell + 1 adds 20 to the address value. Another way of expressing this is to say that tell is type pointer-to-short, or short *, and &tell is type pointer-to-array-of-20-shorts, or short (*)[20].
Now you might be wondering about the genesis of that last type description. First, here is how you could declare and initialize a pointer of that type:
short (*pas)[20] = &tell // pas points to array of 20 shorts
If you omit the parentheses, precedence rules would first associate [20] with pas, making pas an array of 20 pointers-to-short, so the parentheses are necessary. Next, if you wish to describe the type of a variable, you can use the declaration of that variable as a guide and remove the variable name. Thus, the type of pas is short (*)[20]. Also note that because pas is set to &tell, *pas is equivalent to tell, so (*pas)[0] would be the first element of the tell array.
In short, using new to create an array and using a pointer to access the different elements is a simple matter. You just treat the pointer as an array name. Understanding why this works, however, is an interesting challenge. If you actually want to understand arrays and pointers, you should review their mutual relationships carefully.
Summarizing Pointer Points
You’ve been exposed to quite a bit of pointer knowledge lately, so let’s summarize what’s been revealed about pointers and arrays to date.
Declaring Pointers
To declare a pointer to a particular type, use this form:
Here are some examples:
double * pn; // pn can point to a double value
char * pc; // pc can point to a char value
Here pn and pc are pointers, and double * and char * are the C++ notations for the types pointer-to-double and pointer-to-char.
Assigning Values to Pointers
You should assign a memory address to a pointer. You can apply the & operator to a variable name to get an address of named memory, and the new operator returns the address of unnamed memory.
Here are some examples:
double * pn; // pn can point to a double value
double * pa; // so can pa
char * pc; // pc can point to a char value
double bubble = 3.2;
pn = &bubble // assign address of bubble to pn
pc = new char; // assign address of newly allocated char memory to pc
pa = new double[30]; // assign address of 1st element of array of 30 double to pa
Dereferencing Pointers
Dereferencing a pointer means referring to the pointed-to value. You apply the dereferencing, or indirect value, operator (*) to a pointer to dereference it. Thus, if pn is a pointer to bubble, as in the preceding example, then *pn is the pointed-to value, or 3.2, in this case.
Here are some examples:
cout << *pn; // print the value of bubble
*pc = 'S'; // place 'S' into the memory location whose address is pc
Array notation is a second way to dereference a pointer; for instance, pn[0] is the same as *pn. You should never dereference a pointer that has not been initialized to a proper address.
Distinguishing Between a Pointer and the Pointed-to Value
Remember, if pt is a pointer-to-int, *pt is not a pointer-to-int; instead, *pt is the complete equivalent to a type int variable. It is pt that is the pointer.
Here are some examples:
int * pt = new int; // assigns an address to the pointer pt
*pt = 5; // stores the value 5 at that address
Array Names
In most contexts, C++ treats the name of an array as equivalent to the address of the first element of an array.
Here is an example:
int tacos[10]; // now tacos is the same as &tacos[0]
One exception is when you use the name of an array with the sizeof operator. In that case, sizeof returns the size of the entire array, in bytes.
Pointer Arithmetic
C++ allows you to add an integer to a pointer. The result of adding one equals the original address value plus a value equal to the number of bytes in the pointed-to object. You can also subtract an integer from a pointer to take the difference between two pointers. The last operation, which yields an integer, is meaningful only if the two pointers point into the same array (pointing to one position past the end is allowed, too); it then yields the separation between the two elements.
Here are some examples:
int tacos[10] = {5,2,8,4,1,2,2,4,6,8};
int * pt = tacos; // suppose pf and tacos are the address 3000
pt = pt + 1; // now pt is 3004 if a int is 4 bytes
int *pe = &tacos[9]; // pe is 3036 if an int is 4 bytes
pe = pe - 1; // now pe is 3032, the address of tacos[8]