24A. Physical Parameter Passing Modes

Call by value

Normally, when a parameter is passed to a function, the value of that parameter is copied into a variable in the function's frame. For example, if successor is defined by

  int successor(int n)
  {
    return n+1;
  }
then statement
  r = successor(5);
is performed as follows.

  1. A frame for successor is created in the run-time stack. Within that frame is a spot to store parameter n.

  2. Parameter n in the new frame is set to hold 5.

  3. The body of successor begins running. It computes n+1, or 6.

  4. Successor returns 6. The result is copied into a place where the caller can get it. Then the frame for successor is destroyed, and the caller resumes.

  5. The caller gets the result of successor and stores it into variable r.

C++ allows a function's body to change the value of a call-by-value parameter. It only changes the variable in the function's frame, and has no effect other than that. But keep in mind that the coding standards for this course require a function not to change the value of any call-by-value parameter.

Call by pointer

Call by pointer is a special case of call by value where the value that is passed is a pointer. Call by pointer allows a function access to memory via the pointer. Here is a version of successor, renamed incp, that takes a pointer of type int*.

  void incp(int* n)
  {
    *n = *n + 1;
  }
Suppose another function calls incp as follows.
  int w = 1;
  incp(&w);
When incp is called, its parameter n holds the address of the caller's variable w, which means that *n is same as w. So, for this call, statement
  *n = *n + 1;
is equivalent to
  w = w + 1;
After calling incp(&w), the caller finds that w is 2.

Call by reference

Call by pointer allows function F to give function G access to one or more of F 's variables. But it is clumsy. As you can see from the definition of incp above, each time you use a call-by-pointer variable, you need to write a * in front of it. Also, when calling incp, you need to be sure to pass the address of a variable explicitly, using operator &.

C++ provides another calling mode, call by reference, which allows F to call G, passing a variable (a pointer) to G in a way that does not require the asterisks in the body of G and does not require F to use & when calling G.

To request call by reference, write & after the type instead of an asterisk. Here is a function called incr that is similar to incp, but uses call by reference instead of call by pointer.

  void incr(int& n)
  {
    n = n + 1;
  }
Suppose function F performs the following statements.
  int w = 1;
  incr(w);
Here is what happens.

  1. F creates variable w and initializes to 1.

  2. A frame is created for incr. In that frame there is a spot for parameter n.

  3. The memory address of the caller's variable w is stored in n in the new frame. Any reference to n will automatically use variable w.

  4. The body of incr begins to run. It needs to get the value of n so that it can add 1 to n. But n holds a memory address. The value at that memory address (which is the value of the caller's variable w) is fetched.

  5. Expression n+1 evaluates to 2. Now incr needs to store that into n. But since n is a reference parameter, it is a memory address. Value 2 is stored in the memory at that address (which is where w is stored). So w is set to hold 2.

  6. Incr returns to its caller and its stack frame is destroyed.

The parameter of incr is an implicit pointer. The compiler manages it for you. When incr is called, its parameter must be a variable, and that variable's memory address is passed to incr. Any time incr's body uses the parameter, it uses the variable that was passed to incr.

Syntactically, a function body treats reference parameters as if they are local variables. That way, even programmers who are not familiar with pointers can use call by reference.

Exercises

  1. Where are a function's call-by-value parameters stored? Answer

  2. What does jump() return, where jump is writtten below, using function jumpHelper?

     void jumpHelper(int x)
     {
       x = x + 1;
     }
    
     void jump()
     {
       int z = 40;
       jumpHelper(z);
       return z;
     }
    
    Answer

  3. What does hop() return, where hop is writtten below, using function hopHelper?

     void hopHelper(int& x)
     {
       x = x + 1;
     }
    
     void hop()
     {
       int z = 40;
       hopHelper(z);
       return z;
     }
    
    Answer

  4. What does romp() return, where romp is written below, using function rompHelper?

     void rompHelper(int a, int& b)
     {
       b = a + 2;
       a = b + 1;
     }
    
     int romp()
     {
       int x = 4;
       int y = 25;
       rompHelper(x,y);
       return x + y;
     }
    
    Answer