C++ · Functions
Functions and parameters
Trace an int copy, an int reference and a received return value using the same data, then check which variables change after each call.
Practice this topic in the app Read the lesson in the app
Function inputs, processing and return values
Imagine a function is a vending machine: you insert money (arguments), the machine runs according to a fixed procedure (the function body), and finally dispenses a drink (the return value). Each time you insert a different denomination, you get a different result.
When to use it? When the same piece of logic needs to be used several times in a program, extract it into a function to avoid copy-pasting.
Pass by value vs pass by reference: an ordinary parameter is a "photocopy"—changing it inside the function does not affect the outside; a reference parameter with & added is the "original"—changing it inside the function also changes the outside.
Pointer parameters: void update(int* p) receives a copy of the address; through *p you can modify the object the address points to; but directly assigning another address to p only changes the pointer copy inside the function. You can use a const reference to pass in a large read-only object and reduce copying. Defining a function should also state the parameter constraints, the return result, and how null pointers are handled.
Pass by value vs pass by reference: trace the same input
A function receives inputs and executes its body. If it returns a value, the caller can receive that result. Start with n=4: an ordinary int parameter holds a copy, so changing it does not change the caller's n. An int& parameter is another name for the caller's object. Predict n and result before tracing the calls.
| Step | Inside the function | n afterward | result |
|---|---|---|---|
| int n = 4; | No call yet | 4 | Not declared |
| int result = byValue(n); | Copy 4, add 2, return 6 | 4 | 6 |
| byReference(n); | Add 2 to n through the reference | 6 | 6 |
| n = byValue(n); | Copy 6, add 2, then assign returned 8 to n | 8 | 6 |
First error: assuming a parameter with the same name as an outer variable must be the same object. Check its declared type and binding. Second error: assuming a call automatically updates the original variable just because it returns a value. Receive or explicitly assign the result if it should be saved.
This example concerns ordinary int value parameters, not a claim that all by-value functions lack external effects: a copied pointer can still point to an external object. Assigning to a bound reference changes its object rather than rebinding the reference. Returning a value is often clear when calculating a new result; choose a suitable writable reference when modifying the caller's object is intended. Do not return a reference to a local variable. These fixed-count integer operations take O(1); not all functions or copies of all types do.
Run and check: change a copy, change the original, receive a result
#include <iostream>
int byValue(int value) { value += 2; return value; }
void byReference(int& value) { value += 2; }
int main() {
int n = 4;
int result = byValue(n);
std::cout << n << " " << result << "\n";
byReference(n);
std::cout << n << " " << result << "\n";
n = byValue(n);
std::cout << n << " " << result << "\n";
}The lines are 4 6, 6 6 and 8 6. result stores its own value; it does not track later changes to n.
Try before revealing each answer
If the parameter value is renamed n, does pass by value become pass by reference?
No. Names do not change the parameter rules for int versus int&; identical names can denote different objects.
With n=10, what is n after calling byValue(n) without receiving the return value?
Still 10. The function returns 12, but that result is not assigned back to n.
After int& alias=n; alias=9;, is n changed or is alias rebound to 9?
n becomes 9, and alias still refers to that n. Assignment does not rebind an initialized reference.
Calls, references and parameter examples
Example 1: Calculate the sum of two numbers
#include <iostream>
using namespace std;
// Define a function: receive two integers and return their sum
int add(int a, int b) {
return a + b;
}
int main() {
int x = 3, y = 5;
cout << add(x, y) << endl; // output 8
cout << add(10, 20) << endl; // output 30
return 0;
}When calling add(3,5), a=3 and b=5 are photocopies, and the function returns 8; when calling add(10,20) again, the arguments are replaced with 10 and 20, the function still runs, and returns 30.
Example 2: Swap two numbers using reference parameters
#include <iostream>
using namespace std;
// Reference parameters: a and b refer to caller objects
void swap2(int &a, int &b) {
int tmp = a;
a = b;
b = tmp;
}
int main() {
int x = 3, y = 7;
swap2(x, y);
cout << x << " " << y << endl; // output 7 3
return 0;
}Because reference parameters are used, modifications to a and b inside the function directly affect x and y in main, so the output becomes 7 3.
Example 3: Modifying the pointed-to object vs modifying the pointer itself
#include <iostream>
using namespace std;
void update(int* p) {
if (p != nullptr) *p += 1;
p = nullptr; // Change only the local pointer copy
}
int main() {
int x = 4; int* p = &x;
update(p); update(nullptr);
cout << x << " " << (p == &x) << endl;
}Output 5 1. x is modified through dereferencing, and the outer p still points to x; the function also checks for null pointers.
Tips
- Function names should be "self-explanatory", for example calcArea (calculate area) is much clearer than f1.
- Changing an ordinary int value parameter changes only its copy. Use a reference parameter to modify the caller's int. A pointer parameter can also modify its pointed-to object by dereferencing it; see the example.
- A function must be declared (or defined) before use, otherwise the compiler will not recognize it when it sees the call.
- Writing void as the return type means the function does not return anything and only performs operations.
Technical references
Scope note
This lesson is written by InfoCode and is not an official syllabus; the reference level is a site mapping and does not represent official levels, certification or eligibility. Practice records do not establish mastery or eligibility.
Reference level: GESP Level 4 (site mapping)