next up previous
Next: About this document ... Up: Pointers, Arrays, and References Previous: References

Subprogram Linkage

Now we return to the Newton-Raphson code and discuss in more detail the mechanics of passing subprogram arguments.

We start by examining pointer arguments. Suppose we call the subprogram with

   f_and_df(x, &f, &df);
and the subprogram is defined as
   void f_and_df(double x, double *fp, double *dfdxp){
When control is passed from the calling program to the subprogram it is as though the following declarations with initialization take place:
   double x(subprogram) = x(calling program);
   double *fp(subprogram) = &f(calling program);
   double *dfdxp(subprogram) = &dfdx(calling program);
(The comments in parentheses here are not C++ code!) So the declarations of the formal arguments x, fp, and dfdxp are turned into a combination declaration plus initialization.

There is an important difference between these implied declaration/initializations and the ones we discussed before. The formal subprogram arguments do not have permanent memory allocated to them. Instead, temporary space called a "stack" is created for them. Figure [*] shows a possible storage for the variables in memory and the contents of the stack for the case that the initial value of x is $-5.312$ and zero for f and dfdx. After the stack is set up, control is passed to the subprogram, which works only with the contents of the stack. When control is returned to the calling program, the stack is immediately discarded. Please note that the contents are not copied back.


The temporary stack makes it more challenging to get output values from the subprogram. To see this, suppose the subprogram tries to change the value of x with the assignment

   x = 305;
That would attempt to make x both an input and output value. The assignment only changes the number for x in the stack. The original value in the calling program memory is untouched. And when control is returned to the calling program the changed stack is discarded. The original value of x is still unchanged.

Now we can understand the rationale behind pointers. If we hand the address of the variable to the subprogram, the subprogram can use it to access the variable itself. With the assignment

   *fp = 4*x - cos(x);         // the * dereferences the pointer
the subprogram looks up the address specified by fp (22 in the above example) and puts the answer there. Since fp points to f the value of f is changed.

References make the job easier. The subprogram definition

 void f_and_df(double x, double &fr, double &dfdxr)
instructs the compiler to treat the second and third arguments as though they were the same as the variables in the calling statement. The calling statement
     f_and_df(x, f, dfdx);
is treated as a declaration with initialization like this:
   double x (subprogram) = x (calling program);
   double &fr (subprogram) = f (calling program);
   double &dfdxr (subprogram) = dfdx (calling program);
So just as with the reference variable g in the simple example above, when we assign a value to fr it is really f that is being changed.

While we have concentrated on using pointers and references only for output arguments so far, they can also be used as input and for arguments that are dual purpose: input and output. For example, to use pointers for all the arguments we would define the function this way:

// The definition of the subprogram
void f_and_df(double *xp, double *fp, double *dfdxp){
   *fp = 4*(*xp) - cos(*xp);         // the * dereferences the pointer
   dfdxp = 4 + sin(*xp);
and call it with ampersands on all arguments f_and_df(&x,&f,&df);. Notice that it is necessary to dereference the pointer to x in the expressions on the rhs. For readability and to avoid ambiguities, it is a good idea to put parentheses around the dereferenced values in the expressions, as we have done.

Later we will see how to pass arrays as arguments.

next up previous
Next: About this document ... Up: Pointers, Arrays, and References Previous: References
Carleton DeTar 2007-08-17