C++: References
Last updated: 2026-08-26
Pointers are powerful, but somewhat cumbersome — you need to write
*pto dereference, and watch out for null pointers.C++ introduced references — "aliases" for variables that are safer and simpler to use than pointers.
1. What is a Reference?
(1) 1.1 References in Everyday Life
| Real-life Analogy | Program Equivalent |
|---|---|
| You have a nickname "Xiaoming" — calling either name finds you | Reference (alias for a variable) |
| The name on your ID card vs. your everyday name | Reference and the original variable |
Essence of a reference: A reference is an alias for a variable — operating on the reference is operating on the referenced variable.
(2) 1.2 Why Do We Need References?
Using pointers (cumbersome):
▶ Example 2: Code Example (Difficulty ⭐)
#include <iostream>
void modifyValue(int* x) {
*x = 100; // Need dereference
}
int main() {
int a = 5;
modifyValue(&a); // Need to pass address
std::cout << a << std::endl; // 100
return 0;
}
Output:
(Program output)
Using references (simple):
#include <iostream>
void modifyValue(int& x) { // x Is a reference
x = 100; // Use directly,No dereference needed
}
int main() {
int a = 5;
modifyValue(a); // Looks like pass by value,Actually pass by reference
std::cout << a << std::endl; // 100
return 0;
}
2. Reference Declaration and Initialization
(1) 2.1 Declaring a Reference
Syntax:
Type& Reference name = originalVariable;
Example:
#include <iostream>
int main() {
int x = 5;
int& ref = x; // ref is alias of x
std::cout << "x = " << x << std::endl; // 5
std::cout << "ref = " << ref << std::endl; // 5
ref = 100; // modifying ref modifies x
std::cout << "After modification x = " << x << std::endl; // 100
return 0;
}
💡 Key point: References must be initialized — you cannot declare first and assign later.
(2) 2.2 References vs Pointers
| Comparison | Reference | Pointer |
|---|---|---|
| Syntax | int& ref = x; |
int* p = &x; |
| Can be null? | ❌ No (must initialize) | ✅ Yes (nullptr) |
| Need dereferencing? | ❌ No (use directly) | ✅ Yes (*p) |
| Can rebind? | ❌ No (once bound, cannot change) | ✅ Yes (can point to another variable) |
| Recommendation | ⭐⭐⭐⭐⭐ (prefer) | ⭐⭐⭐ (use when necessary) |
3. References as Function Parameters*
(1) 3.1 Basic Usage
#include <iostream>
// Use reference parameters to "return" multiple values
void minMax(int arr, int length, int& min, int& max) {
min = arr[0];
max = arr[0];
for (int i = 1; i < length; i++) {
if (arr[i] < min) {
min = arr[i];
}
if (arr[i] > max) {
max = arr[i];
}
}
}
int main() {
int arr[5] = {3, 1, 4, 1, 5};
int min, max;
minMax(arr, 5, min, max); // min and max will be modified
std::cout << "Minimum: " << min << std::endl; // 1
std::cout << "Maximum: " << max << std::endl; // 5
return 0;
}
💡 Key point: Reference parameters allow functions to "return" multiple values (by modifying multiple reference parameters).
(2) 3.2 const References (Most Commonly Used)
If you don't want the function to modify the parameter, but still want to avoid the cost of copying, use a const reference.
#include <iostream>
#include <string>
void printName(const std::string& name) { // const reference: Cannot modify name
std::cout << "Name: " << name << std::endl;
// name = "Alice"; // ❌ Error: Cannot modify const reference
}
int main() {
std::string myName = "MOTO";
printName(myName); // No need to copy entire string, more efficient
return 0;
}
💡 Golden rule: Prefer const references for function parameters — balancing safety and efficiency.
4. Pitfalls of References*
(1) 4.1 References Must Be Initialized*
#include <iostream>
int main() {
int& ref; // ❌ Error: Reference requires initialization
return 0;
}
Compiler error message:
error: 'ref' declared as reference but not initialized
(2) 4.2 References Cannot Be Rebound*
#include <iostream>
int main() {
int x = 5;
int y = 10;
int& ref = x;
ref = y; // ❌ This is NOT rebinding! This changes x's value to y's value
std::cout << "x = " << x << std::endl; // 10
std::cout << "y = " << y << std::endl; // 10
return 0;
}
💡 Key point: Once a reference is bound to a variable, it cannot be rebound to another variable.
5. Practice: Multiple Return Values*
▶ Example 1: Calculating Quotient and Remainder (Difficulty ⭐⭐)
#include <iostream>
// Use reference parameters to "return" multiple values
void divide(int a, int b, int& quotient, int& remainder) {
quotient = a / b;
remainder = a % b;
}
int main() {
int a = 17, b = 5;
int q, r;
divide(a, b, q, r); // q and r will be modified
std::cout << a << " / " << b << " = " << q << " ... " << r << std::endl;
// Output:17 / 5 = 3 ... 2
return 0;
}
Output:
/ = ...
▶ Example 3: Reference as Function Return Value (Difficulty ⭐)
#include <iostream>
#include <string>
std::string name = "Zhang San"; // Global variable
// Return reference (not value)
std::string& getName() {
return name; // Returns a reference to name
}
int main() {
getName() = "Li Si"; // Modify global variable
std::cout << "name = " << name << std::endl;
return 0;
}
Output:
name =
❓ FAQ
Q: What's the real difference between references and pointers? A:> - References are aliases for variables; pointers are variables that store addresses > - References must be initialized; pointers can be
nullptr> - References cannot be rebound; pointers can > - Prefer references unless you need to represent "nothing" (then use pointers) Q: Why can't arrays be passed by reference as parameters? A: They can, but the syntax for array references is complex.Simpler approach: Use
std::arrayorstd::vector(covered later).
Q: Do references improve runtime efficiency? A: No. References are typically implemented as pointers under the hood, so runtime efficiency is the same.
What they improve is development efficiency (code is cleaner, less error-prone).
Q: What's the most important thing about references? A: Understand the core concepts first, then reinforce them through practice examples.
📖 Summary
- References are aliases for variables; they must be initialized at declaration
- References vs pointers: references cannot be null, cannot be rebound
- References as function parameters: modify external variables, avoid copying
- const references can bind to temporary objects (extending their lifetime)
- Reference return values can be used as lvalues
📝 Exercises
-
Basic (Difficulty ⭐): Write a function
void addTen(int& x)that adds 10 to the passed variable. Test it inmain. -
Intermediate (Difficulty ⭐⭐): Write a function
void swap(int& a, int& b)that swaps two variables' values. Test it inmain. -
Challenge (Difficulty ⭐⭐⭐): Write a program that implements "sort three numbers":
-
Write a function
void sortThree(int& a, int& b, int& c)that sorts three numbers in ascending order -
In
main, let the user enter three numbers, callsortThree, then output the sorted result
6. 🚀 Next Step*
Now that you've learned references, let's move on to Dynamic Memory Allocation (Lesson 26) — managing memory manually with new and delete, and understanding the difference between the stack and the heap.