35 Intermediate The Hundred
The Array That Became a Pointer
same array, same operator, two different answers
#include <iostream>
void measure(int arr[10]) { std::cout << "inside measure: " << sizeof(arr) << " bytes\n"; }
int main() {
int arr[10] = {};
std::cout << "inside main: " << sizeof(arr) << " bytes\n";
measure(arr);
}
Run it. What does it print?
Answer
40 bytes, then 8 bytes. Inside the function, the "array" is the size of a pointer.
Why¶
Array parameters are a polite fiction inherited from C: void measure(int arr[10]) is
rewritten by the compiler to void measure(int* arr), and the 10 is discarded
entirely — you can pass an int[3] and it compiles without a peep. At the call site the
array decays to a pointer to its first element, so inside the function sizeof(arr)
is sizeof(int*) — 8 on x86-64, not 40. The classic casualty is the element-count
idiom: sizeof(arr) / sizeof(arr[0]) inside the function yields 2, and a loop bounded
by it silently processes two elements out of ten.
GCC flags this even with no -W flags at all (-Wsizeof-array-argument is on by
default): "'sizeof' on array function parameter 'arr' will return size of 'int'"* —
and the warning header shows the rewritten signature: In function 'void measure(int*)'.
The fix¶
Pass the array by reference — the size becomes part of the type, so sizeof works and
mismatched sizes are rejected at compile time:
Or skip raw arrays: take a std::array<int, 10>& (or a std::span<int> in C++20), or
compute std::size(arr) at the call site, where the array is still an array.
Takeaway: an array parameter is a pointer wearing an array's clothes — the declared size means nothing.
Try it: g++ -std=c++17 main.cpp -o demo && ./demo