How to Pass Pointers to Functions in C++

By Stephen R. Davis

One of the uses of pointer variables in C++ is in passing arguments to functions. To understand why this is important, you need to understand how arguments are passed to a function.

Passing by value in C++

By default, arguments are passed to functions by value. This has the somewhat surprising result that changing the value of a variable in a function does not normally change its value in the calling function. Consider the following example code segment:

void fn(int nArg)
    nArg = 10;
    // value of nArg at this point is 10
void parent(void)
    int n1 = 0;
    // value of n1 at this point is still 0

Here the parent() function initializes the integer variable n1 to 0. The value of n1 is then passed to fn(). Upon entering the function, nArg is equal to 0, the value passed. fn() changes the value of nArg to 10 before returning to parent(). Upon returning to parent(), the value of n1 is still 0.

The reason for this behavior is that C++ doesn’t pass a variable to a function. Instead, C++ passes the value contained in the variable at the time of the call. That is, the expression is evaluated, even if it is just a variable name, and the result is passed.

In the example, the value of n1, which is 0, was passed to fn(). What the function does with that value has no effect on n1.

Passing pointer values in C++

Like any other intrinsic type, a pointer may be passed as an argument to a function:

void fn(int* pnArg)
  *pnArg = 10;
void parent(void)
   int n = 0;
   fn(&n);      // this passes the address of i
                // now the value of n is 10

In this case, the address of n is passed to the function fn() rather than the value of n. The significance of this difference is apparent when you consider the assignment within fn().

Suppose n is located at address 0x100. Rather than the value 10, the call fn(&n) passes the value 0x100. Within fn(), the assignment *pnArg = 10 stores the value 10 in the int variable located at location 0x100, thereby overwriting the value 0. Upon returning to parent(), the value of n is 10 because n is just another name for 0x100.

Passing by reference in C++

C++ provides a shorthand for passing arguments by address — a shorthand that enables you to avoid having to hassle with pointers. The following declaration creates a variable n1 and a second reference to the same n1 but with a new name, nRef:

int n1;            // declare an int variable
int& nRef = n1;    // declare a second reference to n1
nRef = 1;          // now accessing the reference
                   // has the same effect as accessing n1;
                   // n1 is now equal to 1

A reference variable like nRef must be initialized when it is declared because every subsequent time that its name is used, C++ will assume that you mean the variable that nRef refers to.

Reference variables find their primary application in function calls:

void fn(int& rnArg)// declare reference argument
    rnArg = 10;    // change the value of the variable...
}                  //...that rnArg refers to
void parent(void)
    int n1 = 0;
    fn(n1);        // pass a reference to n1
                   // here the value of n1 is 10

This is called passing by reference. The declaration int& rnArg declares rnArg to be a reference to an integer argument. The fn() function stores the value 10 into the int location referenced by rnArg.

Passing by reference is the same as passing the address of a variable. The reference syntax puts the onus on C++ to apply the “address of” operator to the reference rather than requiring the programmer to do so.

You cannot overload a pass by value function with its pass by reference equivalent. Thus, you could not define the two functions fn(int) and fn(int&) in the same program. C++ would not know which one to call.