| Section II: Using Pointers | Section I: Memory Allocation and the Pointer | Section III: Arrays and Pointers | Section IV: Strings |
|
Table of Contents
Learning C++:
An Index of Entry Points
2. The A reference document on the basic elements of C++.
3. The Patterns
|
A. Assigning Values to Pointers
This would be extremely dangerous if, it were allowed. It would
be saying you want to be able to access memory location 324 or, as we will
see in a bit, be able to put a value into this memory location. But, what
if address 324 is part of the operating system or part of your program. If
you could change it, you would be changing the code for the operating
system or the program, and it is most unlikely that the change would be
for the better. So, we are, in general, not allowed to choose which memory
locations we have direct access to. Instead, we ask the system to provide
us with memory that it knows is free. We can then do what we want with
that memory without worrying about possible bad effects. C++ provides an instruction for making such a request. If you want to
ask for enough memory for a double and store the address of that memory
location in 'ptrDouble', you write:
If you want to ask for enough memory for a contract and store the
address of that memory location in 'ptrContract' you write:
The same is true for any other pointer type. Although 'new' was referred to above as an instruction, it really is an
operator - the same as '+', '-', etc. At this point, however, that is not
very important. What is important is what this 'new' operator does. When
the operator is called, two things happen:
Consider again the code:
When the 'new' operator is called here, the system allocates enough
memory for a double. Assume that the allocated memory begins with the byte
address 54,366. This value is then placed in the variable 'ptrDouble' and
we get the usual picture:
Often, programmers do not include the type in variable names so one
might write:
or even:
This is legal, just as any other declaration/initialization is legal.
What is not legal is, for example:
In this case, you are trying to put the address of an integer into a
variable that has been declared to hold a pointer to a character. As we
said above, a pointer variable can only hold the address of the type it
was declared to hold. To request enough memory for an array of some type, a slightly
different form of the 'new' operator is used. Since the address returned
will point to the first byte of the array, the pointer declaration remains
the same. Thus, if you want a pointer to an array of integers, you can
declare your pointer as:
The change is that you must include the size of the array in the 'new'
statement. Thus, if you want to request enough memory for ten integers,
you write:
To declare and assign a pointer to twenty contracts, one could
write:
There are two other ways to assign a value to a pointer. First, it is
also legal to write:
This means that, for the moment, 'ptr1' points to nothing; it holds the
null pointer. (If the 'new' operator fails in its attempt to
allocate enough memory for whatever is to be pointed to, it returns the
null pointer.) Later, we will see a number of uses for this null pointer
value. The third legal way to assign a value to a pointer is by assigning the
value of one pointer variable to another - as long as they are both of the
same type. Therefore, it is legal to write:
Now both 'ptr1' and ptr2' point to the same memory location.
This also can be quite useful as we will see. B. Accessing Memory Via Pointers In the code:
we first declare 'ptrInt1' to be a pointer to an integer and we can
think of memory as looking as shown in figure 9.5. (The question mark
inside the memory cell indicates that this memory location holds garbage.)
Then we ask the system to provide enough memory to hold an integer and
to assign the address of the first byte of that memory to 'ptrInt1'. Now
memory can be considered to have the form:
Note how the left memory cell now contains an address. The function
'new' set aside the memory with this address and returned this address,
whereupon it was stored in 'ptrInt1'. This new memory (the memory cell on
the right) has not had anything placed in it yet, so it holds garbage.
To store the value five into the memory made available, we would write:
This brings up the distinction between
The first acts like any other variable name and refers to the memory
symbolized by the variable 'intPtr1'. It, thus, refers to the box labeled
"ptrInt1" in figure 9.6, the box containing the address 54366. In
contrast, '*ptrInt1' refers to the address pointed to by the memory
location symbolized by 'ptrInt1'. In other words, '*ptrInt1' refers to the
second box in the figure. When a system sees an asterisk followed by a variable declared to point
to some type, it looks in the variable for an address and follows that
address to a memory location. Therefore,
means "Go to the memory location symbolized by the variable 'ptrInt1'
and get the address stored there. Then go to the memory location with that
address and put the value five in it. After this code is executed, the
picture changes to:
Now consider this code:
The semantics of the last line here are as follows: When the instructions are finished, the 5 in the memory location
pointed to by ptrInt1' has been added to the 4 and the result has been
placed in the memory location pointed to by 'ptrInt2'. The results are
shown in figure 9.8. Notice that in this figure the memory addresses are
not included. This is the way these figures should be drawn, indicating
that we do not know the actual memory locations used.
This process of 'following a pointer' to get to a memory location is
called dereferencing the pointer and a dereferenced pointer
can be used anywhere a variable can be used. For example, consider the
following code:
We will see code similar to this in a bit. For the moment, just
remember that:
Topics Covered in the "Essentials of C++" |