Recommended resources
The freely available resources this lesson will direct you to.
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:
- 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. - 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)). - 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.

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:
- Define a function named
calculatethat accepts four arguments: twointvalues (aandb) and twointpointers (sum_ptrandproduct_ptr). - Inside the
calculatefunction, compute the sum ofaandband store it in the memory location pointed to bysum_ptr. - Compute the product of
aandband store it in the memory location pointed to byproduct_ptr. - In
main, declare variables for the two numbers and for the results (sum_result,product_result). - Call your
calculatefunction, passing the addresses of your result variables. - Print the results in
mainto 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.