Hello! Welcome to the fifth lesson in our module on Pointers and Functions.
In our last lesson, we explored how passing an array to a function is incredibly efficient because C doesn't copy the array; it "decays" the array name into a pointer to its first element. A key consequence we noted was that this gives the function the power to modify the caller's original array.
Today, we will generalize that powerful concept. While a C function can only return a single value, we'll learn how to use pointer parameters to effectively return multiple values from a function. This is a fundamental C idiom you'll see in countless APIs, including those used in firmware, drivers, and the AUTOSAR frameworks you're familiar with.
The "One Return" Limitation and the Pointer Solution
A core design feature of C functions is that they can only have one return value. You cannot, for example, write return area, perimeter;. This limitation requires a different strategy when a computation naturally produces multiple results.
The solution leverages what we've already seen: if a function has the memory address of a variable, it can change that variable's value. We can use this to our advantage by passing pointers to variables that we want the function to fill in. These are often called output parameters.
The process involves three key steps:
- In the calling function (e.g.,
main): Declare local variables to hold the multiple results. - During the function call: Pass the memory addresses of these variables to the function using the address-of operator (
&). - In the called function: Define the parameters as pointers (e.g.,
int *,double *). Inside the function, use the dereference operator (*) to access and write values into the caller's variables.
Let's watch a video that demonstrates this entire workflow with a simple, clear example.
How To "Return" More Than One Value From A Function | C Programming Example
This video from Portfolio Courses clearly explains the problem of returning a single value and demonstrates the standard pointer-based solution. It refactors a simple function that calculates a rectangle's area into a more capable function that computes both area and perimeter.
Watch the entire video. Pay close attention to these key steps: Defining the function to accept pointer parameters (int *area, int *perimeter). Calling the function from main by passing the addresses of local variables (&area_result, &perimeter_result). Using the dereference operator (*) inside the function to assign values back to the caller's variables.
As the video showed, this technique is a powerful way to work around C's single-return limit. You've likely encountered this pattern before with scanf, which uses the same mechanism to place user input into your variables.
A Practical Example: Finding Min and Max
Let's apply this to a slightly more complex problem that combines today's topic with the previous one on arrays. Imagine you need to find both the minimum and maximum values in a large array of sensor readings. Making two passes over the data (one for min, one for max) is inefficient. A single pass is better, but this produces two results. This is a perfect use case for output parameters.
The following resource provides a complete C program to solve this exact problem.
Return multiple value from function – using pointers
This article from Codeforwin.org provides a practical code example for a function that finds both the minimum and maximum values in an array in a single pass.
Study the C code under the heading 'Return multiple value from function – using pointers'. Analyze the getMinMax function signature and see how it uses pointer parameters int *min and int *max to deliver its results to main.
Let's break down the key parts of the getMinMax function:
- Function Signature:
void getMinMax(int * numbers, int size, int * min, int * max)int * numbers: An input parameter for the array (decays to a pointer).int size: An input parameter for the array's size.int * min,int * max: Output parameters, pointers to where the results should be stored.
- Function Body:
*min = *(numbers + 0);The function uses the dereference operator to initialize the caller'sminvariable with the value of the first element of the array.if(*(numbers + i) < *(min)) *min = *(numbers + i);Inside the loop, if a smaller element is found, the function again uses the dereference operator to update the caller'sminvariable. The same logic applies tomax.
This pattern—receiving data via pointers/arrays and returning results via other pointers—is central to many C APIs.
Test your understanding!
Imagine you're writing a function for an ADAS system. The function, get_radar_target, analyzes radar data and needs to provide the closest target's distance (a float), relative speed (a float), and an internal tracking ID (a uint32_t).
The function should also return a status code: 0 for success (target found) and -1 for failure (no target in range).
- Write the function prototype for
get_radar_target. - Show how you would declare the necessary variables in
mainand how you would call this function.
Show answer
-
Function Prototype:
The status code is a natural fit for the function's return value. The three data values will be output parameters.
#include <stdint.h> // For uint32_t int get_radar_target(float *distance, float *speed, uint32_t *id); -
Declaration and Call in
main:int main() { float target_dist; float target_speed; uint32_t target_id; int status; // Call the function, passing addresses of our variables status = get_radar_target(&target_dist, &target_speed, &target_id); if (status == 0) { printf("Target found: ID=%u, Distance=%.2f m, Speed=%.2f m/s\n", target_id, target_dist, target_speed); } else { printf("No target found.\n"); } return 0; }
Common Design Patterns
The exercise above illustrates a very common and robust design pattern. You aren't limited to just one way of doing this. A discussion on Stack Overflow highlights the main variations.
How do I return multiple values from a function in C?
The technique of returning multiple values is flexible. This Stack Overflow discussion provides a good overview of the common patterns that C programmers use.
Read the answers labeled 'Option 2' and 'Option 3' from user 'codaddict'. 'Option 3' shows the pattern we used for the min/max function: a void function returning all values through pointers. 'Option 2' shows the hybrid approach from our exercise: returning a primary value (like a status code) directly, and other data via pointers.
To summarize the patterns:
- All Output Parameters: The function has a
voidreturn type, and all results are communicated through pointer arguments. This is simple and clear when all return values are of a similar nature.
void get_min_max(int arr[], int size, int *min_out, int *max_out); - Hybrid (Status Return + Output Parameters): The function's
returnvalue is used for a status or error code, while the actual data is returned via pointers. This is excellent for functions that can fail, as it allows for clean error-checking:if (do_something(&val) != SUCCESS) { ... }.
Alternative: Returning a Pointer to a Structure
There is another way to return multiple values: group them into a struct, allocate memory for the struct on the heap using malloc(), and return a single pointer to that struct.
This approach is also valid but shifts the burden of memory management. The caller is now responsible for free()-ing the memory later to prevent a memory leak. We will cover this in detail in the next module on Dynamic Memory Management. For now, let's just get a conceptual preview.
Pointers as function returns in C/C++
As a brief look ahead, this video segment from mycodeschool shows how you can safely return a pointer from a function if the memory it points to was allocated on the heap.
Watch from 12:45 to 14:15. The example returns a pointer to a single integer, but the same principle applies to a struct containing multiple values. Notice how malloc is used to get memory that survives the function call. We will explore malloc and free thoroughly in Module 4.
For most cases, especially when the number of return values is small, using output parameters is often simpler and avoids the overhead of dynamic allocation.
Conclusion
You've now mastered a crucial C programming technique that overcomes the language's single-return limitation. This pattern is essential for writing clean, efficient, and robust functions.
Key Takeaways:
- To "return" multiple values from a C function, you pass pointers to variables in the caller's scope. These are called output parameters.
- The caller is responsible for declaring the variables to hold the results and passing their addresses (
&) to the function. - The function defines its parameters as pointers (
*) and uses the dereference operator to write the calculated values back into the caller's variables. - A common and robust pattern is to use the function's direct return value for a status/error code and use pointer parameters for the actual data results.
In our next and final lesson of this module, we will put this knowledge to immediate use by implementing a classic utility function: swapping the values of two variables. This simple task is impossible without the pointer techniques you've learned today.