Skip to content

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:

void measure(int (&arr)[10]);   // sizeof(arr) == 40; passing an int[3] won't compile

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

Open in Compiler Explorer ↗ Quiz this entry