// The first half of this lesson is redundant with https://test.learncpp.com/cpp-tutorial/74-passing-arguments-by-address/
In prior lessons, we’ve covered pass by value
(2.3 -- Introduction to function parameters and arguments) and pass by reference
(8.7 -- Pass by reference and return by reference).
There is one more way to pass variables to functions, and that is by address. Pass by address involves passing the address of the argument variable rather than the argument variable itself. Because the argument is an address, the function parameter must be a pointer. The function can then dereference the pointer to access or change the value being pointed to.
Here is an example of a function that takes a parameter passed by address:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#include <iostream> void foo(int* ptr) // The function parameter is a pointer { *ptr = 6; } int main() { int x{ 5 }; std::cout << "value = " << value << '\n'; foo(&x); // note that we're passing the address of x here std::cout << "value = " << value << '\n'; return 0; } |
The above snippet prints:
value = 5 value = 6
Much like pass by (non-const) reference, passing by address the function to change the value of the argument. Unlike pass by value
where a copy of the argument is made, here we just pass the argument’s address, so when that address is dereferenced, we have access to the actual argument, not a copy.
Checking your parameters for null values
Consider the the following program:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <iostream> void print(int* ptr) { std::cout << *ptr; } int main() { int x{ 5 }; print(&x); print(nullptr); return 0; } |
When this program is run, it will print the value 5
and then exhibit undefined behavior (most likely crash).
In the second call to print()
, we’re passing a nullptr
value, which makes parameter ptr
a null pointer. When this null pointer is dereferenced in the body of print()
, undefined behavior results.
When passing a parameter by address, it’s a good idea to always check to ensure it’s not a null value before you dereference the value.
One way to do that is to use a conditional statement:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#include <iostream> void print(int* ptr) { if (!ptr) // if ptr is a null pointer, early return back to the caller return; std::cout << *ptr; } int main() { int x{ 5 }; print(&x); print(nullptr); return 0; } |
An alternate (and in many cases, better) method is to use an assert
, which we cover in lesson %Failed lesson reference, id 5845%.
Passing by pointer to const
In the case of the print()
function from the prior example, since the function does not modify the value being pointed to, we really should make the function parameter a pointer to const
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#include <iostream> void print(const int* ptr) // now a pointer to a const int { if (!ptr) // if ptr is a null pointer, early return back to the caller return; std::cout << *ptr; } int main() { int x{ 5 }; print(&x); print(nullptr); return 0; } |
This allows us to tell at a glance that print()
won’t modify the argument passed in, and will ensure that we don’t do so by accident.
Prefer pass by reference
Note that function print
in the example above doesn’t handle null values very well -- it effectively just aborts the function. Given this, why allow a user to pass in a null value at all? Unless a function needs to handle both normal and null values, pass by reference
is preferable to pass by address
because it is safer.
Best practice
Prefer pass by reference
to pass by address
unless your function needs to handle null values.
Return by address
Return by address works almost identically to return by reference (covered in lesson 8.7 -- Pass by reference and return by reference), except a pointer is returned instead of a reference. Return by address has the same caveats as return by reference -- the object being returned must outlive the scope of the function, otherwise the caller will receive a dangling pointer.
Return by address is typically only used in two situations:
- When returning a parameter passed in by address
- When returning a member pointer from a class object (we’ll cover this in a future lesson)
![]() |
![]() |
![]() |
Leave a Reply