Because pointers are so important in C and C++, this chapter will review
some of the more important topics concerning pointers. Even if you are
extremely conversant in the use of pointers, you should not completely
ignore this chapter because some new material unique to C++ is presented
here.

POINTER REVIEW

Example program ------> POINTERS.CPP

Examine the program named POINTERS.CPP for a simple example of the use
of pointers. This is a pointer review and if you are comfortable with the
use of pointers, you can skip this example program completely.

A pointer in either ANSI-C or C++ is declared with an asterisk preceding
the variable name. The pointer is then a pointer to a variable of that
one specific type and should not be used with variables of other types.
Thus pt_int is a pointer to an integer type variable and should
not be used with any other type. Of course, an experienced C programmer
knows that it is simple to coerce the pointer to be used with some other
type by using a cast, but he must then assume the responsibility for its
correct usage.

In line 12 the pointer named pt_int is assigned the address of
the variable named pig and line 13 uses the pointer named pt_int
to add the value of dog to the value of pig because the asterisk
dereferences the pointer in exactly the same manner as standard C. Figure
3-1 is a graphical representation of the data space following execution
of line 13. Note that a box containing a dot represents a pointer. The
address is used to print out the value of the variable pig in line
14 illustrating the use of a pointer with the output stream object cout.
Likewise, the pointer to float named pt_float is assigned
the address of x, then used in a trivial calculation in line 18.

CONSTANT POINTERS AND POINTERS TO CONSTANTS

The definition of C++ allows a pointer to a constant to be defined such
that the value to which the pointer points cannot be changed but the pointer
itself can be moved to another variable or constant. The method of defining
a pointer to a constant is illustrated in line 22. In addition to a pointer
to a constant, you can also declare a constant pointer, one that cannot
be changed. Line 23 illustrates this. Note that neither of these pointers
are used in illustrative code.

Either of these constructs can be used to provide additional compile
time checking and improve the quality of your code. If you know a pointer
will never be moved due to its nature, you should define it as a constant
pointer. If you know that a value will not be changed, it can be defined
as a constant and the compiler will tell you if you ever inadvertently
attempt to change it.

A POINTER TO VOID

The pointer to void is actually a part of the ANSI-C standard
but is relatively new so it is commented upon here. A pointer to void
can be assigned the value of any other pointer type. You will notice
that the pointer to void named general is assigned an address
of an int type in line 15 and the address of a float type
in line 20 with no cast and no complaints from the compiler. This is a
relatively new concept in C and C++. It allows a programmer to define a
pointer that can be used to point to many different kinds of things to
transfer information around within a program. A good example is the malloc()
function which returns a pointer to void. This pointer can be assigned
to point to any entity, thus transferring the returned pointer to the correct
type.

A pointer to void is aligned in memory in such a way that it
can be used with any of the simple predefined types available in C++, or
in ANSI-C for that matter. They will also align with any compound types
the user can define since compound types are composed of the simpler types.

If you are not completely comfortable with this trivial program using
pointers, you should review the use of pointers in any good C programming
book or Coronado Enterprises C tutorial before proceeding on because we
will assume that you have a thorough knowledge of pointers throughout the
remainder of this tutorial. It is not possible to write a C program of
any significant size or complexity without the use of pointers.

Be sure to compile and execute this program.

DYNAMIC ALLOCATION AND DEALLOCATION

Example program ------> NEWDEL.CPP

Examine the program named NEWDEL.CPP for our first example of the new
and delete operators. The new and delete operators
do dynamic allocation and deallocation in much the same manner that the
malloc() and free() functions do in your old favorite C implementation.

During the design of C++, it was felt that since dynamic allocation
and deallocation are such a heavily used part of the C programming language
and would also be heavily used in C++, it should be a part of the language,
rather than a library add-on. The new and delete operators
are actually a part of the C++ language and are operators, much like the
addition operator or the assignment operator. They are therefore very efficient,
and are very easy to use as we will see in this example program.

Lines 15 and 16 illustrate the use of pointers in the tradition of C
and line 17 illustrates the use of the new operator. This operator
requires one modifier which must be a type as illustrated here. The pointer
named point2 is now pointing at the dynamically allocated integer
variable which exists on the heap, and can be used in the same way that
any dynamically allocated variable is used in ANSI-C. Lines 19 and 20 illustrate
displaying the value on the monitor which was assigned in line 18.

Line 21 allocates another new variable and line 22 causes point2
to refer to the same dynamically allocated variable as point1 is
pointing to. In this case, the reference to the variable that point2
was previously pointing to has been lost and it can never be used or
deallocated. It is lost on the heap until we return to the operating system
when it will be reclaimed for further use, so this is obviously not good
practice. Note that point1 is deallocated with the delete operator
in line 26, and point2 can not be deleted since it is now pointing
to nothing. Since the pointer point1 itself is not changed, it is
probably still pointing to the original data on the heap. This data could
probably be referred to again using point1, but it would be terrible
programming practice since you have no guarantee what the system will do
with the pointer or the data. The data storage is returned to the free
list to be allocated in a subsequent call, and will soon be reused in any
practical program.

Since the delete operator is defined to do nothing if it is passed
a NULL value, it is legal to ask the system to delete the data pointed
to by a pointer with the value of NULL, but nothing will actually happen.
It is actually wasted code. The delete operator can only be used
to delete data allocated by a new operator. If the delete is
used with any other kind of data, the operation is undefined and anything
can happen. According to the ANSI standard, even a system crash is a legal
result of this illegal operation, and can be defined as such by the compiler
writer.

In line 28, we declare some floating point variables. You will remember
that in C++ the variables do not have to be declared at the beginning of
a block. A declaration is an executable statement and can therefore appear
anywhere in a list of executable statements. One of the float variables
is allocated within the declaration to illustrate that this can be done.
Some of the same operations are performed on these float type variables
as were done on the int types earlier.

Some examples of the use of a structure are given in lines 36 through
44 and should be self explanatory.

Finally, since the new operator requires a type to determine
the size of the dynamically allocated block, you may wonder how you can
allocate a block of arbitrary size. This is possible by using the construct
illustrated in line 48 where a block of 37 char sized entities,
which will be 37 bytes, is allocated. A block of 133 bytes greater than
the size of the date structure is allocated in line 50. It is therefore
clear that the new operator can be used with all of the flexibility
of the malloc() function which you are familiar with. The brackets
are required in lines 49 and 51 to tell the compiler that it is deallocating
an array.

The standard functions which you have been using in C for dynamic memory
management, malloc(), calloc(), and free(), are also
available for use in C++ and can be used in the same manner they were used
in C. If you are updating code with the older function calls, continue
to use them for any additions to the code. If you are designing and coding
a new program you should use the newer constructs because they are a built
in part of the language rather than an add on and are therefore more efficient.
It is an error to delete a variable that has been malloc'ed
and it is an error to free a variable that was allocated with new.

Be sure to compile and execute this program.

POINTERS TO FUNCTIONS

Example program ------> FUNCPNT.CPP

Examine the program named FUNCPNT.CPP for an example of using a pointer
to a function. It must be pointed out that there is nothing new here, the
pointer to a function is available in ANSI-C as well as in C++ and works
in the manner described here for both languages. It is not regularly used
by most C programmers, so it is briefly discussed here as a refresher.
If you are comfortable with the use of pointers to functions, you can skip
this discussion entirely.

There is nothing unusual about this program except for the pointer to
a function declared in line 7. This declares a pointer to a function which
returns nothing (void) and requires a single formal parameter, a
float type variable. You will notice that all three of the functions
declared in lines 4 through 6 fit this profile and are therefore candidates
to be called with this pointer. If you have not used prototyping in C,
these lines will look strange to you. Don't worry about them at this point
since we will study prototyping in the next chapter of this tutorial.

Observe that in line 14 we call the function print_stuff() with
the parameter pi and in line 15 we assign the function pointer named
function_pointer the value of print_stuff and use the function
pointer to call the same function again in line 16. Lines 14 and 16 are
therefore identical in what is accomplished because of the pointer assignment
in line 15. In lines 17 through 22, a few more illustrations of the use
of the function pointer are given. You will be left to study these on your
own.

Since we assigned the name of a function to a function pointer, and
did not get an assignment error, the name of a function must be a pointer
to that function. This is exactly the case. A function name is a pointer
to that function, but it is a pointer constant and cannot be changed. This
is exactly the case we found when we studied arrays in ANSI-C at some point
in our C programming background. An array name is a constant pointer to
the first element of the array.

Since the name of the function is a constant pointer to that function,
we can assign the name of the function to a function pointer and use the
function pointer to call the function. The only caveat is that the return
value and the number and types of parameters must be identical. Most C
and C++ compilers will not, and in fact, can not warn you of type mismatches
between the parameter lists when the assignments are made. This is because
the assignments are done at runtime when no type information is available
to the system, rather than at compile time when all type information is
available.

The use and operation of pointers must be thoroughly understood when
we get to the material on dynamic binding and polymorphism later in this
tutorial. It will be discussed in detail at that time.

Be sure to compile and execute this program.

PROGRAMMING EXERCISES

When dynamically allocated data is deleted, it is still actually in
memory, stored on the heap. Repeat the output statement from lines 24 and
25 of NEWDEL.CPP immediately following the delete in line 26 to see if
the values are really still there. Repeat it once again just prior to the
end of the program when the data spaces should have been written over to
see if you get garbage out. Even if your compiler reports the correct data,
it is terrible practice to count on this data still being there because
in a large dynamic program, the heap space will be used repeatedly.

Add a function to FUNCPNT.CPP which uses a single integer for a parameter
and attempt to call it by using the function pointer to see if you get
the correct data into the function.