If you are learning C++, one of the first questions you’ll face is the difference between pointers and references in C++. Both let you work with objects indirectly, but they serve different purposes and have different rules. In this beginner-friendly guide, you’ll learn what pointers and references are, how they differ, when to use each one, and the common mistakes to avoid. We’ll use simple, runnable examples and clear explanations suitable for students and new C++ learners.
- Pointers can be
nullptrand can be reseated; references cannot. - References express a required, non-null alias; pointers often express “optional”.
- References use normal object syntax (
r.member); pointers need*porp->. - Neither implies ownership; use smart pointers for that.
What is a pointer in C++?
A pointer is a variable that stores the memory address of another object. You can think of it as a “locator” that tells you where a value lives in memory. Because pointers hold addresses, they can be null (point to nothing), changed to point to something else, and even moved around using pointer arithmetic (mainly useful with arrays and low-level tasks).
Why use pointers?
- To represent an optional object (use
nullptrto mean “absent”). - To reassign which object is being accessed (reseat to another address).
- For interoperability with C APIs, arrays, and low-level memory manipulation.
Basic pointer syntax:
- Declare:
T* p; - Point to an object:
p = &obj; - Dereference to access the object:
*porp->member - Null pointer:
T* p = nullptr;(since C++11)
What is a reference in C++?
A reference is an alias to an existing object. After you bind a reference to a variable, it becomes another name for that same variable. A reference must be initialized when created, and you cannot later reseat it to refer to a different object. In ordinary C++, a reference must be bound to a valid object; attempting to treat a null like an object and bind a reference to it leads to undefined behavior.
Why use references?
- To express a required, non-null parameter in your function interface.
- To avoid pointer syntax while still avoiding copying large objects.
- To make code easier to read: accessing a reference looks like normal object access.
Basic reference syntax:
- Declare and bind:
T& r = obj; - Use like a normal variable:
raccesses the originalobj
Pointers vs References: quick comparison
| Feature | Pointer (T*) |
Reference (T&) |
|---|---|---|
| Can be null | Yes (nullptr) |
Must refer to a valid object; “null reference” is undefined behavior |
| Can be reseated | Yes (p = &other;) |
No; bound once at initialization |
| Syntax to access | *p, p->member |
r, r.member |
| Default initialization | Uninitialized until set; can be nullptr |
Must be initialized immediately |
| Pointer arithmetic | Allowed (use carefully) | Not applicable |
| Common use-cases | Optional params, C interop, arrays/buffers | Required params, clear aliasing, readability |
Difference between pointer and reference in C++ with examples
This short program shows the core differences: dereferencing, reseating a pointer, and the fact that references remain bound to the original object.
#class="cd-package">include <iostream>
class="cd-package">using class="cd-package">namespace std;
int main() {
int x = 42;
int y = 100;
int* p = &x; // pointer to x
int& r = x; // reference (alias) to x
cout << "x=" << x << ", r=" << r << ", *p=" << *p << "n";
*p = 7; // change x through the pointer
cout << "after *p=7: x=" << x << ", r=" << r << "n";
p = &y; // reseat pointer to y
r = 9; // writes to x (reference stays bound to x)
cout << "after p=&y and r=9: x=" << x << ", y=" << y
<< ", *p=" << *p << ", r=" << r << "n";
int* q = nullptr; // null pointer is allowed
cout << "q is nullptr? " << (q == nullptr) << "n";
}x=42, r=42, *p=42
after *p=7: x=7, r=7
after p=&y and r=9: x=9, y=100, *p=100, r=9
q is nullptr? 1When to use pointer vs reference (beginner guide)
const T&Writable:
T&T* and check for nullptrstd::unique_ptr<T> or std::shared_ptr<T>, not raw T*/T&.std::reference_wrapper<T>.
- Use a reference (
T&orconst T&) when:- The parameter is required (must be non-null).
- You want simple, object-like syntax (
obj.member). - You’re passing large objects without copying (use
const T&for read-only).
- Use a pointer (
T*) when:- The parameter is optional (use
nullptrto mean “no object”). - You need to reseat which object is referenced by the handle.
- You interact with arrays, C APIs, or do pointer arithmetic.
- The parameter is optional (use
- Do not use raw pointers or references to express ownership. Prefer
std::unique_ptrfor exclusive ownership, orstd::shared_ptrfor shared ownership. Raw pointers and references are non-owning views.
How do pointers and references work in function parameters and return types?
Here are common, practical patterns students will meet frequently:
- Read-only big object:
const T& - Optional parameter or out-parameter:
T*(check fornullptr) - Return a reference to a subobject that outlives the function (e.g., a field of a parameter)
- Return a pointer to indicate “found or not found” (maybe
nullptrwhen absent)
#class="cd-package">include <iostream>
class="cd-package">using class="cd-package">namespace std;
struct Shape {
int w;
int h;
};
void draw(const Shape& s) { // required, read-only
cout << "draw " << s.w << "x" << s.h << "n";
}
void scale(Shape* s, int factor) { // optional: may be nullptr
if (s) {
s->w *= factor;
s->h *= factor;
}
}
Shape* findWide(Shape* arr, int n, int minW) { // may return nullptr
for (int i = 0; i < n; ++i) {
if (arr[i].w >= minW) return &arr[i];
}
return nullptr;
}
int& widthOf(Shape& s) { // safe as long as ___CDPHSTR3___ outlives the reference
return s.w;
}
int main() {
Shape s1{10, 20};
Shape s2{5, 5};
draw(s1); // required argument
scale(&s1, 2); // modify through pointer
draw(s1);
scale(nullptr, 3); // safe: function checks for nullptr
Shape arr[2]{s1, s2};
Shape* found = findWide(arr, 2, 15);
if (found) {
cout << "found width=" << found->w << "n";
} else {
cout << "none foundn";
}
int& wref = widthOf(s2); // reference to s2.w
wref = 30; // modifies s2
cout << "s2 width now " << s2.w << "n";
}draw 10x20
draw 20x40
found width=20
s2 width now 30Choosing parameter types: quick tips
- Small, cheap-to-copy types (e.g.,
int,double, smallstruct): pass by value. - Large read-only objects (e.g.,
std::string,std::vector<T>): pass byconst T&. - Optional or output parameters: use
T*and document thatnullptris allowed; check inside the function. - Non-owning buffer parameters: in modern C++ use
std::span<T>(C++20) orstd::string_viewfor text, instead of rawT*+ length.
Modern C++ notes you should know
nullptr(C++11) is the proper null pointer literal. Prefer it over0orNULL.- Rvalue references (
T&&) enable move semantics. In templates, a parameter of the formT&&with type deduction is a forwarding reference, which preserves lvalue/rvalue-ness withstd::forward. - Ownership: Prefer
std::unique_ptrandstd::shared_ptrto express owning relationships. Raw pointers and references are non-owning handles. - Reseatable “reference-like” handle needed? Consider
std::reference_wrapper<T>(e.g., in containers) when you want reference syntax but need reseating behavior by reassigning the wrapper object.
Common mistakes with pointers and references in C++
- Dereferencing a null pointer. Always check a
T*before using*porp->if it may benullptr. - Returning a reference to a local variable. The local dies at function end, leaving a dangling reference. Return by value or return a reference to something that still exists.
- Assuming you can reseat a reference.
r = other;assigns to the bound object; it does not change whatrrefers to. - Using raw pointers or references to express ownership. Prefer smart pointers.
- Pointer arithmetic on non-arrays. Only use pointer arithmetic within the bounds of the same array (or one past the end for iteration, not dereference).
#class="cd-package">include <iostream>
class="cd-package">using class="cd-package">namespace std;
// Wrong (do not do this):
/*
int& badFunc() {
int local = 42;
return local; // ERROR: returns reference to a dead local (dangling reference)
}
*/
// Correct alternatives:
// - Return by value: int goodFunc() { int local = 42; return local; }
// - Or return a reference to a valid, longer-lived object passed in.
struct Holder { int value; };
int& refToValue(Holder& h) {
return h.value; // OK: ___CDPHSTR0___ lives outside, so returned reference is valid while ___CDPHSTR1___ lives
}
void setIfNotNull(int* p, int v) {
if (p) *p = v; // check before dereference
}
int main() {
Holder h{10};
int& r = refToValue(h);
r = 99; // modifies h.value
int* maybe = nullptr;
setIfNotNull(maybe, 5); // safe: function checks
cout << "h.value=" << h.value << "n";
}h.value=99Pointer vs reference in C++: simple rules of thumb
- If a function requires a parameter and will not accept “no object,” prefer
T&orconst T&. - If “no object” is a valid case, prefer
T*and document/checknullptr. - Don’t use raw pointers or references to claim ownership; use smart pointers.
- For buffers, prefer modern non-owning views like
std::spanandstd::string_viewwhen available.
- Required parameter →
T&orconst T&. Optional →T*and checknullptr. - Never return a reference or pointer to a local variable.
- Use
nullptr(C++11+) instead of0orNULL. - Do not use raw pointers/references for ownership; prefer
std::unique_ptr/std::shared_ptr. - For buffers/views prefer
std::span<T>andstd::string_viewwhen available. - Avoid pointer arithmetic unless iterating within the same array bounds.
FAQ: Pointers vs References (for beginners)
What is the main difference between a pointer and a reference in C++?
A pointer is an object that holds an address; it can be nullptr and can be reseated to a different address. A reference is an alias bound at initialization to a valid object; it cannot be reseated and does not support nullptr in a defined way. That’s the core difference between pointers and references in C++.
When should I use a pointer instead of a reference?
Use a pointer when the parameter is optional (can be absent), when you need to reseat the handle to another object, when interfacing with C APIs, or when performing array-style operations. Otherwise, use references for required parameters and clear, non-null aliasing.
Can a C++ reference be null or changed to refer to another variable?
No to both in ordinary, well-formed C++. A reference must be bound to a valid object on initialization and cannot be reseated. Creating a “null reference” leads to undefined behavior and should be avoided.
How do pointers and references work in function parameters and return types?
- Parameters: use
const T&for required read-only,T&for required writable, andT*for optional writable/readable parameters. - Return types: return a reference only if you’re returning a subobject that will outlive the function call; otherwise, return by value. Return a pointer when you want to signal “found or not found” (
nullptr).
Which is safer for beginners, pointers or references in C++?
References are usually safer as function parameters because they can’t be null and don’t require dereferencing syntax. Pointers are more flexible but require careful handling of nullptr and lifetimes. For ownership, prefer smart pointers rather than raw pointers.
Further tips and next steps
Practice by refactoring a few functions in your own code to use references for required parameters and pointers for optional ones. When you’re ready, explore move semantics (T&&) and modern non-owning views like std::span and std::string_view. For more beginner-friendly C++ tutorials, visit our C++ learning section on CodDesire.
Sources / Further reading
- cppreference: Pointers — https://en.cppreference.com/w/cpp/language/pointer
- cppreference: References — https://en.cppreference.com/w/cpp/language/reference
- cppreference: nullptr — https://en.cppreference.com/w/cpp/language/nullptr
- Microsoft Learn: Pointers (C++) — https://learn.microsoft.com/en-us/cpp/cpp/pointers-cpp?view=msvc-170
- Microsoft Learn: References (C++) — https://learn.microsoft.com/en-us/cpp/cpp/references-cpp?view=msvc-170
- C++ Core Guidelines — https://isocpp.org/guidelines
By now, you should have a clear picture of pointers vs references in C++, including what a pointer is in C++, what a reference is in C++, and how to choose pointer or reference in C++ functions. Keep practicing, and this core concept will soon feel natural.


