Memory & Language Features
References
Complete lesson for References using LEARNCODEGURU’s 6-level learning model — from basics to advanced practice, with C++ OOP and STL where relevant.
Basics — References
Section: Memory & Language Features. C++ references — aliases, binding rules, pass-by-reference, const references, and vs pointers.
What is a reference?
- A **reference** is an **alias** (another name) for an existing object.
- Syntax:
int& r = x;—randxrefer to the **same** memory. - Changing
rchangesx(and the other way around). - A reference **must** be initialized when created and **cannot** be reseated to another object later.
- **Real-life analogy:** a nickname for a person — “Ravi” and “Raju” for the same student; update one identity, same person.
- **Real-life analogy:** two labels stuck on the same box — both names mean that one box.
| Idea | Syntax | Meaning |
|---|---|---|
| Declare & bind | int& r = x; | r is another name for x |
| Use | r = 20; | Changes x as well |
| Read | cout << r; | Same value as x |
| Address | &r | Same address as &x (usually) |
#include <iostream>
using namespace std;
int main() {
int x = 10;
int& r = x; // r is an alias for x
r = 25;
cout << "x = " << x << "\n"; // 25
cout << "r = " << r << "\n"; // 25
cout << (&x == &r ? "same address\n" : "different\n");
return 0;
} Why we need references
- **Modify caller’s variables** cleanly (swap, update balance) without pointer
*/->syntax. - **Avoid copying** large objects when passing to functions (
string,vector, structs). - Express “this parameter **must** refer to a real object” — references are not null in normal use.
- Used heavily in operator overloading, range-based for, and STL APIs.
| Need | Without references | With references |
|---|---|---|
| Swap two ints | Pointers + * clutter | void swap(int& a, int& b) |
| Pass a big string | Copy is expensive | void print(const string& s) |
| Update balance | Return new value or use pointer | void deposit(int& bal, int amt) |
| Loop & edit elements | Index or pointers | for (int& x : v) x *= 2; |
Binding rules (important)
- A non-const reference must bind to an **lvalue** (a named object you can assign to) — not a temporary like
int& r = 10;(invalid). - Once bound,
r = y;**assigns through** the reference (changes the original object); it does **not** makerrefer toy. - You cannot have a “null reference” in ordinary C++ — always bind to a valid object.
- A reference is not an object that stores an address you manage; think “another name,” not “reseatable pointer.”
int x = 5, y = 9;
int& r = x; // OK — binds to x
r = y; // assigns 9 into x; r still aliases x
// int& bad = 10; // ERROR — cannot bind non-const ref to temporary Pass by reference
- Function parameters as
T&let the function read/write the caller’s object. - **Real-life:** editing a shared form online — both “names” see the same fields update.
- Compare with pass by value (copy) from the Functions lesson.
#include <iostream>
using namespace std;
void bump(int& n) { n++; }
void swap(int& a, int& b) {
int t = a; a = b; b = t;
}
int main() {
int x = 10;
bump(x);
cout << x << "\n"; // 11
int p = 1, q = 2;
swap(p, q);
cout << p << " " << q << "\n"; // 2 1
return 0;
} const references
const T&means: alias the object but **do not modify** it through this name.- Best default for read-only function inputs of large types — no copy, no accidental change.
constreferences can bind to temporaries:const string& s = string("hi");(lifetime extended in that context).- **Real-life:** a “view only” link to a document — you can read, not edit.
#include <iostream>
#include <string>
using namespace std;
void greet(const string& name) {
cout << "Hello, " << name << "!\n";
// name += "!"; // ERROR — const
}
int main() {
string user = "Ravi";
greet(user);
greet("Guest"); // temporary bound to const string&
return 0;
} Differences between references and pointers
- Both can refer to another object; references are stricter and often cleaner for required aliases.
| Point | Reference (T&) | Pointer (T*) |
|---|---|---|
| What it is | Alias / another name | Variable storing an address |
| Must init? | Yes, at creation | Should, but can be uninitialized (bad) |
| Null? | No (normally) | Yes — nullptr |
| Reseat to other object? | No | Yes — p = &y; |
| Syntax to use object | r directly | *p or p-> |
| Arithmetic | No | Yes (p+1) |
| Dynamic allocation | Does not own new memory | Can hold new result |
| Typical API use | Required in/out params | Optional / reseatable / arrays |
| Real-life | Permanent nickname | Sticky note with an address you can replace |
References in range-based for
for (auto x : v)copies each element;for (auto& x : v)aliases and can modify.for (const auto& x : v)read-only without copying — preferred for big elements.
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> v = {1, 2, 3};
for (int& x : v) x *= 2; // modify
for (const int& x : v) cout << x << " "; // 2 4 6
return 0;
} Return by reference (careful)
- A function may return
T&to allow chaining or avoid copies — but the referred object must **outlive** the use. - **Never** return a reference to a local variable — it is destroyed when the function ends (dangling).
- OK to return a reference to a parameter that was passed in by reference, or to a static/global (rare), or to a member of
*thisin a class.
int& first(int& a, int& b) {
return (a < b) ? a : b; // OK — refers to caller's object
}
// BAD:
// int& bad() {
// int local = 5;
// return local; // dangling
// } Which should you use?
- Pick the tool that matches ownership and nullability.
| Situation | Prefer | Why |
|---|---|---|
| Must update caller’s variable | T& | Clear, non-null alias |
| Read-only large object | const T& | No copy, no modify |
| Optional object / may be absent | T* or optional | Can be null / empty |
| Reseat / walk an array | T* | Pointer arithmetic / reseating |
| Own heap memory | smart pointer / container | RAII ownership |
Advanced — References
lvalue references vs rvalue references (overview)
- Classic
T&is an **lvalue reference** — binds to named objects. - C++11 **
T&&** is an rvalue reference — used for move semantics and perfect forwarding (advanced/move lesson territory). - For this topic, master
T&andconst T&first — they cover most everyday APIs.
const correctness patterns
const T&for input;T&for in/out; returnTby value for new results (NRVO/moves often make this cheap).- Do not take
T&if you only read — callers cannot pass temporaries or const objects. - Overload pairs sometimes exist:
T& f();andconst T& f() const;in classes.
#include <string>
using namespace std;
string shout(const string& s) { // input only
return s + "!";
}
void appendBang(string& s) { // in/out
s += "!";
} References, arrays, and structs
- You can have a reference to an array element:
int& cell = a[i]; - Reference members in a class must be bound in the constructor initializer list.
- A reference parameter to a struct lets you update fields without copying the whole struct.
struct Account {
int balance;
};
void deposit(Account& a, int amount) {
a.balance += amount;
} Common pitfalls
- Thinking
r = yreseats the reference — it assigns to the bound object. - Returning a reference to a local — dangling alias.
- Using a reference after the original object’s lifetime ended.
- Taking non-const ref to a temporary — compile error (use const ref or value).
Real-life models
- Bank account update:
void withdraw(Account& a, int amt). - Shopping cart:
void addItem(Cart& cart, const Item& item)— cart edited, item read-only. - Game player stats:
void heal(Player& p, int hp)modifies the same player object. - Config viewer:
void show(const Settings& s)— display without copying or changing.
Tricky Interview Points
Q1) What is a reference in C++?
Answer An alias for an existing object. Declared like int& r = x; it must be initialized and cannot be reseated to another object.
Q2) Why use references?
Answer To modify caller objects cleanly, avoid copying large objects (especially const T&), and express non-null required parameters.
Q3) Difference between a reference and a pointer?
Answer A reference is a non-reseatable alias and is not null in normal use. A pointer stores an address, can be nullptr, can be reseated, and uses * / ->.
Q4) What does r = y do if r is a reference to x?
Answer It assigns the value of y into x. r still refers to x — it does not start referring to y.
Q5) What is a const reference?
Answer const T& is a read-only alias. It avoids copies for large inputs and prevents modification through that name. It can bind to temporaries.
Q6) Can a reference be null?
Answer Ordinary references must bind to a valid object. There is no nullptr for references like there is for pointers.
Q7) Can you reseat a reference?
Answer No. After int& r = x; the statement r = y; changes x’s value; it does not make r alias y.
Q8) When is pass by const reference preferred?
Answer When a function only reads a potentially large object (string, vector, struct) and should not modify it.
Q9) Is returning a reference to a local variable safe?
Answer No. The local is destroyed when the function returns, leaving a dangling reference.
Q10) How do references help in range-based for?
Answer for (auto& x : v) lets you modify elements; for (const auto& x : v) reads without copying.
Q11) Pass by value vs pass by reference?
Answer By value copies the argument; changes inside do not affect the caller. By reference aliases the caller’s object; changes do affect it.
Q12) Give a real-life example of a reference.
Answer A nickname for the same person, or a “view/edit” link to the same shared document.
Simple Programs
Alias — change via reference
#include <iostream>
using namespace std;
int main() {
int marks = 80;
int& m = marks;
m += 5;
cout << marks << "\n"; // 85
return 0;
} Pass by reference — deposit
#include <iostream>
using namespace std;
void deposit(int& balance, int amount) {
balance += amount;
}
int main() {
int bal = 1000;
deposit(bal, 250);
cout << bal << "\n"; // 1250
return 0;
} swap with references
#include <iostream>
using namespace std;
void swap(int& a, int& b) {
int t = a; a = b; b = t;
}
int main() {
int x = 3, y = 7;
swap(x, y);
cout << x << " " << y << "\n";
return 0;
} const string& — no copy greet
#include <iostream>
#include <string>
using namespace std;
int wordCount(const string& s) {
int spaces = 0;
for (char ch : s) if (ch == ' ') spaces++;
return s.empty() ? 0 : spaces + 1;
}
int main() {
cout << wordCount("Learn Tech Guru") << "\n";
return 0;
} Range-for with references
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> v = {5, 10, 15};
for (int& n : v) n += 1;
for (const int& n : v) cout << n << " ";
return 0;
} Struct updated by reference
#include <iostream>
#include <string>
using namespace std;
struct Student {
string name;
int marks;
};
void addBonus(Student& s, int bonus) {
s.marks += bonus;
}
int main() {
Student st{"Asha", 90};
addBonus(st, 5);
cout << st.name << " " << st.marks << "\n";
return 0;
} Return reference to smaller of two
#include <iostream>
using namespace std;
int& minRef(int& a, int& b) {
return (a < b) ? a : b;
}
int main() {
int x = 8, y = 3;
minRef(x, y) = 0; // sets the smaller one to 0
cout << x << " " << y << "\n"; // 8 0
return 0;
} Problem Solving Tricks
- Read
T&as “another name for a T”. - Always initialize a reference at the declaration.
- Remember:
r = yassigns through r; it does not reseat r. - Default for big read-only inputs:
const T&. - Use
T&when the function must update the caller’s object. - Prefer references over pointers when null is not meaningful.
- Never return a reference to a local variable.
- In range-for, use
auto&to edit andconst auto&to read big elements. - If you need optional/absent, use a pointer or std::optional — not a reference.
- Same address of
&xand&ris a good mental check that they alias. - Keep reference parameters named clearly: balance, cart, player.
- Do not take non-const ref just for “style” when you only read.
Practice Programs List
- Create an int and a reference to it; modify both ways and print.
- Write deposit/withdraw functions that take int& balance.
- Implement swap with references for two doubles.
- Write printTitle(const string& title) and call it with a literal and a variable.
- Use range-for with int& to square every element of a vector.
- Pass a Student struct by reference and update marks; pass by const reference to print.
- Show that r = y does not reseat: print &r before and after.
- Write minRef(a,b) returning int& and use it on the left of an assignment.
- Attempt (and fix) returning a reference to a local — explain why it is wrong.
- Compare a function with string by value vs const string& — discuss copies.
- Build Cart with addItem(Cart&, const string& item).
- List five API signatures using T& or const T& for a small school app.
- Explain in comments why references cannot be null and cannot be reseated.
- Rewrite a pointer-based update function to use references instead.