Pointers: Indirection & nullptr
পয়েন্টার — ঠিকানা ধরে কাজ
1. Memory Is a Big Array of Bytes
Imagine RAM as a giant numbered array. Every byte has an address. A pointer is just a variable that holds an address.
2. The & and * Operators
#include <iostream>
int main() {
int x = 42;
int* p = &x; // p holds the address of x
std::cout << "x = " << x << "\n";
std::cout << "&x = " << &x << "\n"; // address
std::cout << "p = " << p << "\n"; // same address
std::cout << "*p = " << *p << "\n"; // dereferences → 42
*p = 100; // modifies x via pointer
std::cout << "x now = " << x << "\n";
}
3. nullptr — The Null Pointer
A pointer that points to nothing. Always initialize pointers!
#include <iostream>
int main() {
int* p = nullptr;
if (p) std::cout << *p;
else std::cout << "p is null\n";
}
*p when p == nullptr = undefined behavior. On most systems it crashes (segmentation fault). Always check before dereferencing.
nullptr in modern C++. NULL is a macro = 0, which causes overload resolution bugs.
4. Smart Pointer Preview
Modern C++ rarely uses raw pointers for ownership. Instead use std::unique_ptr (sole owner) or
std::shared_ptr (shared owner). They free memory automatically when they go out of scope.
#include <iostream>
#include <memory>
int main() {
auto p = std::make_unique<int>(42);
std::cout << *p << "\n";
// no delete needed — auto-cleanup at scope end
}
Module 17 covers smart pointers in depth.
5. When to Use Raw Pointers
- Non-owning observation — pointing into a container, optional access.
- C API interop — when the API requires it.
- Polymorphic traversal in legacy code.
For ownership: use smart pointers. For "must point to something": use references.
6. Practice Problems
- Declare a pointer to an int and have it point to a variable.
✨ Show Answer
int x = 5; int* p = &x; - What's
sizeof(int*)on a 64-bit system?✨ Show Answer
8 bytes. All pointers (whatever they point to) have the size of the address bus — 8 bytes on 64-bit, 4 bytes on 32-bit.
- What is undefined behavior in
int* p; std::cout << *p;?✨ Show Answer
pis uninitialized → it holds garbage. Dereferencing reads from a random memory location. UB. Always initialize:int* p = nullptr;. - Use a pointer to swap two ints.
✨ Show Answer
void swap(int* a, int* b) { int t = *a; *a = *b; *b = t; } // usage: swap(&x, &y);(In modern C++ prefer references — same effect, safer syntax.)
- Why prefer
nullptroverNULL?✨ Show Answer
nullptrhas its own type (std::nullptr_t).NULLis just0, an int — it picks the wrong overload when you havef(int)andf(int*). - What does
p == nullptrtell you?✨ Show Answer
The pointer doesn't point to a valid object. Don't dereference it.
- Print the address of a variable.
✨ Show Answer
std::cout << &x; - Difference between
int* pandint *p?✨ Show Answer
None — just style. Most C++ guides put the
*next to the type:int* p. C convention puts it next to the name:int *p. - What is
int** pp?✨ Show Answer
A pointer to a pointer to int.
**ppdereferences twice to reach the int. - Is
int* p = &5;legal?✨ Show Answer
No.
5is a temporary literal — has no address you can take. - When should you prefer
T*overT&?✨ Show Answer
When you need (a) optional/null, (b) to rebind to point to different objects later, or (c) to interact with a C API.
- Show that modifying via pointer changes the original.
✨ Show Answer
int x = 5; int* p = &x; *p = 10; std::cout << x; // 10 - Pointer to a vector:
std::vector<int>* vp. How to push 5?✨ Show Answer
vp->push_back(5); // arrow = (*vp).push_back - Why use
std::unique_ptrover rawnew/delete?✨ Show Answer
unique_ptrauto-deletes on scope exit (RAII), making leaks impossible. Rawnew/deleterequires manual management — everynewneeds exactly onedelete, easy to forget on early returns or exceptions. - Make a
unique_ptr<int>holding 7.✨ Show Answer
auto p = std::make_unique<int>(7); - Can two raw pointers point to the same int?
✨ Show Answer
Yes — both can hold the same address. They're independent variables holding the same value. Useful for multiple non-owning observers.
- Print the value pointed to and the value of the pointer itself.
✨ Show Answer
std::cout << *p << " " << p; // value, then address - What is a "dangling pointer"?
✨ Show Answer
A pointer to memory that has been freed or to a variable that has gone out of scope. Dereferencing one is UB.
- Function with optional pointer param: print value or "none".
✨ Show Answer
void show(int* p) { if (p) std::cout << *p; else std::cout << "none"; } - Modern alternative for "optional value": ?
✨ Show Answer
std::optional<T>(C++17). It's a value type, not a pointer — no nullability bugs, no allocation.
Summary
A pointer holds an address. Use & to take an address, * to dereference.
Always initialize pointers (use nullptr). For ownership, use smart pointers; for "must exist",
use references; for "may not exist", use std::optional for values or smart pointers for objects.