2.3. Pointers and Functions
Pointer parameters provide a mechanism through which functions can modify argument values. The commonly used pass by pointer pattern uses a pointer function parameter that gets the value of the address of some storage location passed to it by the caller. For example, the caller could pass the address of one of its local variables. By dereferencing the pointer parameter inside the function, the function can modify the value at the storage location to which it points.
We have already seen similar functionality with array parameters, where an array function parameter gets the value of the base address of the passed array (the parameter refers to the same set of array elements as its argument), and the function can modify the values stored in the array. In general, this same idea can be applied by passing pointer parameters to functions that point to the memory locations in the caller’s scope.
Pass by Value
All arguments in C are passed by value and follow pass-by-value
semantics: the parameter gets a copy of its argument value, and
modifying the parameter’s value does not change its argument’s value.
When passing base type values, like the value of an In the pass-by-pointer pattern, the parameter still gets the value of its argument, but it is passed the value of an address. Just like in passing base types, changing a pointer parameter’s value will not change its argument’s value (that is, assigning the parameter to point to a different address will not change the argument’s address value). However, by dereferencing a pointer parameter, the function can change the contents of memory that both the parameter and its argument refer to; through a pointer parameter, a function can modify a variable that is visible to the caller after the function returns. |
Here are the steps for implementing and calling a function with a pass by pointer parameter, with example code snippets showing each step:
-
Declare the function parameter to be a pointer to the variable type:
/* input: an int pointer that stores the address of a memory * location that can store an int value (it points to an int) */ int change_value(int *input) {
-
When making the function call, pass in the address of a variable as the argument:
int x; change_value(&x);
In the preceding example, since the parameter’s type is
int *
, the address passed must be the address of anint
variable. -
In the body of the function, dereference the pointer parameter to change the argument’s value:
*input = 100; // the location input points to (x's memory) is assigned 100
Next, let’s examine a larger example program:
#include <stdio.h>
int change_value(int *input);
int main(void) {
int x;
int y;
x = 30;
y = change_value(&x);
printf("x: %d y: %d\n", x, y); // prints x: 100 y: 30
return 0;
}
/*
* changes the value of the argument
* input: a pointer to the value to change
* returns: the original value of the argument
*/
int change_value(int *input) {
int val;
val = *input; /* val gets the value input points to */
if (val < 100) {
*input = 100; /* the value input points to gets 100 */
} else {
*input = val * 2;
}
return val;
}
When run, the output is:
x: 100 y: 30
Figure 1 shows what the call stack looks like before executing the
return in change_value
.
The input parameter gets a copy of the value of its argument (the address of
x
). The value of x
is 30 when the function call is made. Inside the
change_value
function, the parameter is dereferenced to assign the value 100
to the memory location pointed to by the parameter (*input = 100;
, meaning
"the location input
points to gets the value 100"). Since the parameter
stores the address of a local variable in the main
function’s stack frame,
through dereferencing the parameter, the value stored in the caller’s local
variable can be changed. When the function returns, the argument’s value
reflects the change made to it through the pointer parameter (the value of x
in main
was changed to 100 by the change_value
function through its input
parameter).