Skip to main content

Someone wanted to learn this too, so Grasp built them a personal learning path.

You can keep exploring this one or create your own

Passing Pointers for Pass-by-Reference

Welcome to the next lesson in our exploration of C programming. In the previous session, you successfully used pointers to reverse an array. The function you wrote, void reverseArray(int *arr, int size), worked because you passed the memory address of the array's first element, giving the function direct access to modify the original data.

Today, we will formalize and expand on this powerful concept. You will learn how to pass pointers to functions to allow them to modify their arguments. This technique, often called "pass-by-reference," is fundamental to writing efficient and modular C code. We will explore why simply passing variables to a function isn't enough to change them and how pointers provide the solution.

1. The Problem: C's Pass-by-Value Nature

One of the most important rules in C is that arguments are passed to functions by value. This means that when you call a function, the function receives a copy of each argument's value, not the original variable itself. The function then works with these private copies. Any changes made to these copies inside the function are discarded when the function finishes, and the original variables in the calling function remain completely untouched.

Let's see why this is a problem with a classic programming challenge: swapping the values of two variables.

Understanding Functions, Memory, and Pointers in C

This article from the blog of Jyoti Prakash provides a crystal-clear explanation of pass-by-value, using excellent code examples and memory diagrams.

Read the section "The Truth About Pass By Value", including the subsection "The Classic Swap Problem". Pay close attention to the swap_broken function and the memory visualization diagram that shows why modifying the function's parameters (a and b) has no effect on the original variables (x and y).

As you saw, the swap_broken function successfully swaps its local copies, a and b. However, since these are separate variables in a different part of memory (a different stack frame), the original x and y in main are never affected.

So, how can we give a function the power to reach back and modify its caller's variables?

2. The Solution: Passing Pointers

The solution is not to pass the values themselves, but to pass their memory addresses. If a function knows the address of a variable, it can use a pointer to go to that address and change the value stored there.

This is the essence of simulating pass-by-reference in C. It involves three key steps:

  1. Function Definition: The function's parameters are declared as pointers (e.g., int *ptr). This tells the compiler that the function expects to receive memory addresses.
  2. Function Call: When calling the function, you use the address-of operator (&) to pass the memory address of the variables (e.g., swap(&x, &y)).
  3. Function Body: Inside the function, you use the dereference operator (*) to access and modify the value at the received address (e.g., *ptr = 100;).

Let's see the correct way to implement the swap function.

Swap Two Variables Using Pointers | C Programming Example

This video from Portfolio Courses gives a concise and practical demonstration of creating a swap function using pointers.

Watch the segment from creating the swap function. Notice how the function is defined to accept int * parameters and how it's called using &x and &y.

The video shows the "how." The following image and reading will help you understand the "why" by visualizing the memory layout.

This diagram illustrates how pointers in a function's memory frame (`set_x_and_y`) hold the addresses of variables in the calling function's frame (`f`). By dereferencing these pointers, the function can modify the original variables `a` and `b`.

To get a deep understanding of what's happening, let's return to the article we started with.

Understanding Functions, Memory, and Pointers in C

This part of the article explains the working solution and provides a crucial insight into C's mechanics.

Read the section "'Pass By Reference' is Really Pass By Value of an Address". Study the swap_working function and its corresponding memory diagram. The key takeaway is that C is still passing by valueβ€”but it's passing the value of the address. This address value is copied into the function's pointer parameters, giving them the information needed to modify the original variables.

3. A Broader Application: "Returning" Multiple Values

The ability to modify arguments is useful for more than just swapping. It's a general-purpose tool for any situation where a function needs to communicate more than one piece of information back to its caller.

A function can only have one return value. What if you need to calculate or retrieve two, three, or more values? A common pattern is to pass pointers to variables where the function can store its results. The caller provides the storage, and the function fills it.

For example, imagine a function that needs to get a pair of X/Y coordinates from the user. Instead of trying to return two values, we can pass pointers to the variables that should store the results.




#include <stdio.h>

// This function takes two pointers as arguments.
// It will read two integers from the user and store them
// at the memory addresses provided by the pointers.
void getCoordinates(int *x_ptr, int *y_ptr) {
    printf("Enter the X coordinate: ");
    
    // scanf needs an address to store the input.
    // x_ptr already IS an address, so we just pass it directly.
    scanf("%d", x_ptr);

    printf("Enter the Y coordinate: ");
    scanf("%d", y_ptr);
}

int main(void) {
    int x_coord;
    int y_coord;

    printf("Before calling getCoordinates: x=%d, y=%d\n", x_coord, y_coord);
    // Note: The initial values are garbage because they are uninitialized.

    // We pass the ADDRESSES of our variables to the function.
    getCoordinates(&x_coord, &y_coord);

    printf("\nAfter calling getCoordinates: x=%d, y=%d\n", x_coord, y_coord);

    return 0;
}

Compile and run this code. You will see that the getCoordinates function successfully modifies the x_coord and y_coord variables inside main. This pattern is extremely common in C programming.

4. Your Turn: Calculate Sum and Product

Now it's your turn to apply what you've learned. Your task is to write a function that takes two numbers and "returns" both their sum and their product.

Instructions:

  1. Define a function named calculate that accepts four arguments: two int values (a and b) and two int pointers (sum_ptr and product_ptr).
  2. Inside the calculate function, compute the sum of a and b and store it in the memory location pointed to by sum_ptr.
  3. Compute the product of a and b and store it in the memory location pointed to by product_ptr.
  4. In main, declare variables for the two numbers and for the results (sum_result, product_result).
  5. Call your calculate function, passing the addresses of your result variables.
  6. Print the results in main to verify that they were calculated correctly.

Fill in the missing code below:




#include <stdio.h>

// 1. Define the function prototype.
void calculate(int a, int b, int *sum_ptr, int *product_ptr) {
    // 2. Calculate the sum and store it using the pointer.
    // Your code here.
    
    // 3. Calculate the product and store it using the pointer.
    // Your code here.
}

int main(void) {
    int num1 = 10;
    int num2 = 5;
    
    int sum_result;
    int product_result;
    
    printf("Initial values: sum=%d, product=%d\n", sum_result, product_result);
    
    // 4. Call the 'calculate' function, passing the addresses of the result variables.
    calculate(num1, num2, &sum_result, &product_result);
    
    printf("Calculated values: sum=%d, product=%d\n", sum_result, product_result);
    
    return 0;
}
Click here for the solution to the missing code.
  // Inside the calculate function:
  
  // 2. Calculate the sum and store it using the pointer.
  *sum_ptr = a + b;
  
  // 3. Calculate the product and store it using the pointer.
  *product_ptr = a * b;

Conclusion

In this lesson, you've mastered one of the most essential techniques in C programming: using pointers to allow functions to modify their arguments. This opens up a new level of control and is crucial for building complex, high-performance applications.

Key Takeaways:

  • C is strictly a pass-by-value language; functions always operate on copies of their arguments.
  • To modify a variable from within a function, you must pass a pointer (the variable's memory address) to that function.
  • This technique is often called pass-by-reference, but it's more accurately described as "pass-by-value of an address."
  • The function must declare its parameter as a pointer (e.g., int *p) and use the dereference operator (*p) to access or modify the original data.
  • The caller must use the address-of operator (&var) to pass the argument.
  • This is a common C idiom for functions that need to "return" multiple values.

Preview of the Next Lesson:
Now that you have a firm grasp of how pointers interact with functions and memory, we are ready to build more complex data representations. In the next lesson, you will learn how to define your own custom data types using structs. We will then combine this with our knowledge of pointers to allocate memory for these structs dynamically, giving our programs the flexibility to handle data whose size isn't known at compile time.

Can't find a good explanation? Sign up and we'll make it for you

Sign up