Pointers and Memory Management
Pointers and Arrays
The deep relationship between pointers and arrays in C++
Interview: Fundamental C++ memory model — array decay, pointer arithmetic, and sizeof are common interview questions
Pointers and Arrays
In C++, arrays and pointers have an intimate relationship inherited from C. An array name, in most contexts, decays to a pointer to its first element. This decay is implicit and silent — it's one of the most common sources of subtle bugs and is a frequent interview topic.
Array Decay
When an array is passed to a function, it decays to a T* pointing to the first element. The size information is completely lost. This is why C-style functions always require a separate size parameter: void process(int* arr, int n). The only contexts where decay does NOT happen: sizeof, & (address-of), and binding to a typed array reference.
Equivalence of Expressions
Given int arr[] and int* ptr = arr, the following are all equivalent: arr[i], *(arr + i), ptr[i], *(ptr + i), and even i[arr] (the subscript operator is commutative). This equivalence is a direct consequence of how pointer arithmetic and array indexing are defined.
sizeof — The Key Difference
sizeof(array) gives the total size of the array in bytes. sizeof(pointer) gives the size of the pointer itself (8 bytes on 64-bit). Once an array has decayed, you can no longer recover its size — this is the critical distinction interviewers test.
Interview Corner
Q: What does array decay mean and what information is lost?
A: Array decay is the implicit conversion of an array to a pointer to its first element. The lost information is the array's size — once decayed, the pointer cannot tell you how many elements it points to. This forces C APIs to pass size as a separate parameter. std::array and std::vector solve this by storing size alongside the data.
Q: What is the output of sizeof on an array vs pointer to that array?
A: int arr[5]; sizeof(arr) = 20 (5 × 4 bytes). int* ptr = arr; sizeof(ptr) = 8 (64-bit pointer size). After decay: void f(int arr[]) { sizeof(arr); } — the parameter is actually int*, so sizeof gives 8, not 20. This surprises many developers.
Common Pitfalls
- sizeof inside a function accepting an array: The most common sizeof pitfall —
sizeof(arr) / sizeof(arr[0])gives 2 (pointer/int) inside a function, not the array element count. - Out-of-bounds via pointer arithmetic: Accessing
ptr + nwhere n ≥ array size is undefined behavior — reads garbage or causes a segfault.
Best Practices
- Use
std::arrayorstd::vector— they carry their size and don't decay. - When passing C-style arrays to functions, accept a
const T (&arr)[N]reference template to preserve size:template<std::size_t N> void process(int (&arr)[N]).