Skip to main content

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.

L1

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; — r and x refer to the **same** memory.
  • Changing r changes x (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.
IdeaSyntaxMeaning
Declare & bindint& r = x;r is another name for x
User = 20;Changes x as well
Readcout << r;Same value as x
Address&rSame 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.
NeedWithout referencesWith references
Swap two intsPointers + * cluttervoid swap(int& a, int& b)
Pass a big stringCopy is expensivevoid print(const string& s)
Update balanceReturn new value or use pointervoid deposit(int& bal, int amt)
Loop & edit elementsIndex or pointersfor (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** make r refer to y.
  • 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.
  • const references 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.
PointReference (T&)Pointer (T*)
What it isAlias / another nameVariable storing an address
Must init?Yes, at creationShould, but can be uninitialized (bad)
Null?No (normally)Yes — nullptr
Reseat to other object?NoYes — p = &y;
Syntax to use objectr directly*p or p->
ArithmeticNoYes (p+1)
Dynamic allocationDoes not own new memoryCan hold new result
Typical API useRequired in/out paramsOptional / reseatable / arrays
Real-lifePermanent nicknameSticky 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 *this in 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.
SituationPreferWhy
Must update caller’s variableT&Clear, non-null alias
Read-only large objectconst T&No copy, no modify
Optional object / may be absentT* or optionalCan be null / empty
Reseat / walk an arrayT*Pointer arithmetic / reseating
Own heap memorysmart pointer / containerRAII ownership
L2

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& and const T& first — they cover most everyday APIs.

const correctness patterns

  • const T& for input; T& for in/out; return T by 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(); and const 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 = y reseats 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.
L3

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.

L4

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;
}
L5

Problem Solving Tricks

  • Read T& as “another name for a T”.
  • Always initialize a reference at the declaration.
  • Remember: r = y assigns 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 and const auto& to read big elements.
  • If you need optional/absent, use a pointer or std::optional — not a reference.
  • Same address of &x and &r is 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.
L6

Practice Programs List

  1. Create an int and a reference to it; modify both ways and print.
  2. Write deposit/withdraw functions that take int& balance.
  3. Implement swap with references for two doubles.
  4. Write printTitle(const string& title) and call it with a literal and a variable.
  5. Use range-for with int& to square every element of a vector.
  6. Pass a Student struct by reference and update marks; pass by const reference to print.
  7. Show that r = y does not reseat: print &r before and after.
  8. Write minRef(a,b) returning int& and use it on the left of an assignment.
  9. Attempt (and fix) returning a reference to a local — explain why it is wrong.
  10. Compare a function with string by value vs const string& — discuss copies.
  11. Build Cart with addItem(Cart&, const string& item).
  12. List five API signatures using T& or const T& for a small school app.
  13. Explain in comments why references cannot be null and cannot be reseated.
  14. Rewrite a pointer-based update function to use references instead.