Ch5.7: C‑style Array Decay

Overview

C‑style arrays have a special behavior called array decay. In most expressions, a C‑style array automatically converts (or “decays”) into a pointer to its first element. This is one of the most important rules in C++, and it explains why arrays and pointers often appear interchangeable even though they are not the same.

In this chapter, you will learn:

1. What is C‑style array decay?

When a C‑style array is used in most expressions, it automatically converts into a pointer to its first element.


int a[3]{10, 20, 30};

int *p = a;   // array decays to pointer to a[0]

After decay:


a (array):
Address:   1000
Memory:   [ 10 ][ 20 ][ 30 ]

p (pointer):
Address:   2000
Memory:   [ 1000 ]   ← pointer to a[0]

2. Why does decay happen?

C‑style arrays cannot be copied or assigned. They also cannot be passed by value to functions.

To allow arrays to be used in expressions and function calls, C++ automatically converts them to pointers.

3. When decay happens

Decay happens in most expressions, including:


int a[3]{10, 20, 30};

int *p = a;        // decay
int *q = a + 1;    // decay, then pointer arithmetic
bool same = (a == p);  // decay, then compare pointers

4. When decay does NOT happen

Decay does not happen in the following cases:


int a[3]{10, 20, 30};

std::size_t s1 = sizeof(a);   // 3 * sizeof(int)
std::size_t s2 = sizeof(a[0]); // sizeof(int)

int *p = a;                   // decay
std::size_t s3 = sizeof(p);   // size of pointer, NOT array

Key rule: sizeof(a) gives the size of the entire array. sizeof(p) gives the size of a pointer.

5. Decay in function parameters

You cannot pass a C‑style array by value to a function. Instead, the array decays to a pointer.


void f(int *p);   // receives pointer, not array

int a[3]{10, 20, 30};
f(a);             // a decays to &a[0]

Even if you write:


void g(int a[3]);

it is still interpreted as:


void g(int *a);   // array size is ignored

6. Decay and pointer arithmetic

After decay, the pointer behaves like any other pointer to the first element.


int a[3]{10, 20, 30};

int *p = a;   // decay
int *q = p + 2;

int x = *q;   // 30

This is why array indexing works:


a[i]   // means *(a + i)

Because a decays to a pointer.

7. Using ::std::ranges::begin(a) and ::std::ranges::end(a)

Instead of relying on decay, modern C++ provides explicit functions to obtain iterators for C‑style arrays:


#include 

int a[3]{10, 20, 30};

int *first = ::std::ranges::begin(a);
int *last  = ::std::ranges::end(a);   // one past the end

These functions do not evaluate a[N]. They compute the correct pointers safely:

This is the preferred modern way to obtain iterators for C‑style arrays.

8. Why decay can be dangerous

After decay, the pointer no longer knows the array’s size. This can lead to:

For example:


int a[3]{10, 20, 30};
int *p = a;

std::size_t s = sizeof(p);   // size of pointer, NOT array

This is a common source of bugs.

Key takeaways