Question
In C and C++, what does array-to-pointer conversion, often called array decay, mean? How does it work, and how is it related to pointers to arrays?
Short Answer
By the end of this page, you will understand what array-to-pointer conversion means in C and C++, why arrays are often treated like pointers in expressions, and why an array is still not the same thing as a pointer. You will also learn the difference between a decayed array expression and a pointer to an array, which is a separate type.
Concept
In C and C++, an array and a pointer are closely related, but they are not the same thing.
When an array is used in many expressions, the language automatically converts the array expression into a pointer to its first element. This automatic conversion is called array-to-pointer conversion or array decay.
For example:
int numbers[4] = {10, 20, 30, 40};
int* p = numbers;
Here, numbers is an array of 4 int values. But in the assignment to p, numbers is converted to &numbers[0], which is a pointer to the first element.
So this line behaves like:
int* p = &numbers[0];
Why this matters
This concept matters because it explains several common behaviors:
- Why arrays can be passed to functions that take pointers
- Why
arr[i]works with pointers too - Why
sizeof(arr)is different inside and outside some functions - Why arrays and pointers feel similar but behave differently
Important idea
An array is a real object that stores multiple elements. A pointer is a variable that stores an address.
Array decay does not mean the array becomes a pointer permanently. It means that in certain expressions, the array is converted to a pointer value.
Common conversion result
If you have:
int arr[5];
then in most expressions, arr becomes:
int* // pointer to first element
Cases where decay does not happen
There are important exceptions where the array stays an array:
sizeof(arr)&arrdecltype(arr)in C++typeid(arr)in some C++ contexts- direct initialization of a reference to an array in C++
Example:
int arr[5];
sizeof(arr); // size of the whole array, not pointer size
&arr; // pointer to the whole array, type: int (*)[5]
Relation to pointer to array
This is where many learners get confused.
These two types are different:
int* p; // pointer to int
int (*q)[5]; // pointer to an array of 5 ints
If arr is int arr[5];, then:
arrusually decays toint*&arrisint (*)[5]
So:
int arr[5] = {1, 2, 3, 4, 5};
int* p = arr; // okay
int (*q)[5] = &arr; // okay
They may print similar addresses, but their types are different, and pointer arithmetic behaves differently.
p + 1; // moves by one int
q + 1; // moves by one whole array of 5 ints
That type difference is the key idea.
Mental Model
Think of an array as a row of lockers and a pointer as a piece of paper containing an address.
- The array is the actual row of lockers.
- The pointer is just a stored location.
When array decay happens, the language says:
“If you use the array in this expression, I will give you the address of the first locker.”
That does not mean the row of lockers has turned into paper. The array still exists as a full array. You are just being handed the starting address.
Now think about a pointer to an array as a paper that says:
“Here is the address of the entire row as one unit.”
That is different from:
“Here is the address of the first locker.”
These addresses may look similar, but the meaning of moving forward from them is different:
- from the first locker: move by one element
- from the whole row: move by one whole row
Syntax and Examples
Basic syntax
int arr[3] = {1, 2, 3};
int* p = arr; // array decays to pointer to first element
int* p2 = &arr[0]; // equivalent result
Array and pointer access
#include <iostream>
using namespace std;
int main() {
int arr[3] = {10, 20, 30};
int* p = arr;
cout << arr[0] << "\n"; // 10
cout << p[0] << "\n"; // 10
cout << *(arr + 1) << "\n"; // 20
cout << *(p + 2) << "\n"; // 30
}
Because arr often decays to int*, pointer-style access works.
Step by Step Execution
Consider this example:
#include <iostream>
using namespace std;
int main() {
int arr[3] = {5, 10, 15};
int* p = arr;
int (*q)[3] = &arr;
cout << arr[1] << "\n";
cout << p[1] << "\n";
cout << (*q)[1] << "\n";
}
Step by step
1. Create the array
int arr[3] = {5, 10, 15};
Memory contains three int values in sequence.
arr[0]is5arr[1]is10
Real World Use Cases
Passing arrays to functions
In C and C++ code, arrays are often passed into functions for processing:
void process(int* data, int size);
A real array can be passed because it decays to int*.
Working with buffers
Many programs use character buffers or numeric buffers:
char buffer[256];
Functions often receive a pointer to the first element and then work through the buffer.
Interoperability with low-level APIs
System libraries, C libraries, and embedded code often expect pointers rather than high-level container types. Array decay makes fixed arrays usable with those APIs.
Iterating through contiguous memory
Code that processes image data, sensor data, network packets, or audio samples often treats arrays as a starting address plus length.
Multidimensional arrays
Pointers to arrays become especially important with 2D arrays:
int grid[2][3];
When passed correctly, developers often use pointer-to-array types to preserve row size information.
Real Codebase Usage
In real projects, developers usually rely on this concept in a few common ways.
Function parameters
Traditional C-style functions often use:
void printValues(const int* values, int count);
The caller may pass an array, and it decays automatically.
Guard clauses with pointer inputs
When functions receive pointers, code often validates them early:
void printValues(const int* values, int count) {
if (values == nullptr || count <= 0) {
return;
}
for (int i = 0; i < count; i++) {
std::cout << values[i] << "\n";
}
}
Preserving array size in C++
Because decay loses size information, modern C++ code often prefers references to arrays or containers like std::array and std::vector.
< N>
{
( i = ; i < N; i++) {
std::cout << arr[i] << ;
}
}
Common Mistakes
Mistake 1: Thinking arrays and pointers are identical
They are related, but not identical.
int arr[3] = {1, 2, 3};
int* p = arr;
arris an array objectpis a pointer variable
You cannot assign a new address to arr.
arr = p; // error
Mistake 2: Losing array size in function parameters
void showSize(int arr[]) {
std::cout << sizeof(arr) << "\n";
}
This is misleading. In a function parameter, arr[] is treated like int* arr, so sizeof(arr) gives the size of a pointer, not the whole array.
Mistake 3: Confusing arr with &arr
Comparisons
| Concept | Type example | What it represents | Pointer arithmetic |
|---|---|---|---|
| Array | int arr[5] | 5 actual int values stored together | Not a pointer variable |
| Decayed array expression | arr in many expressions | Pointer to first element | Moves by one element |
| Pointer to element | int* p | Address of an int | Moves by one int |
| Pointer to whole array | int (*q)[5] | Address of an array of 5 int values |
Cheat Sheet
int arr[5]; // array of 5 ints
int* p = arr; // arr decays to int*
int* p2 = &arr[0]; // same address as first element
int (*q)[5] = &arr; // pointer to whole array
Rules to remember
- Arrays are not pointers.
- In many expressions, an array decays to a pointer to its first element.
arrusually becomes&arr[0].&arrmeans address of the whole array.arrand&arrcan print similar addresses, but their types differ.- In function parameters,
int arr[]is treated asint* arr. - After decay, array length information is lost.
No-decay contexts
Decay does not happen with:
sizeof(arr)&arr- array references in C++
decltype(arr)in C++
FAQ
What does array decay mean in C or C++?
It means an array expression is automatically converted to a pointer to its first element in many contexts.
Is an array the same as a pointer?
No. An array is a real object containing elements. A pointer is a variable that stores an address.
What is the difference between arr and &arr?
arr usually decays to a pointer to the first element. &arr is a pointer to the whole array.
Why does sizeof(arr) give a different result from sizeof in a function parameter?
Outside the function, arr is still an array, so sizeof(arr) gives the full array size. In a parameter like int arr[], it is treated as a pointer, so sizeof(arr) gives pointer size.
What is a pointer to an array?
It is a pointer whose target is the entire array object, such as int (*p)[5].
Why do arr and &arr sometimes show the same address?
They can refer to the same starting memory location, but they have different types and different pointer arithmetic behavior.
Mini Project
Description
Build a small C++ program that demonstrates the difference between an array, a decayed array expression, and a pointer to the whole array. This project is useful because many bugs come from treating these types as if they were identical.
Goal
Write a program that prints values, sizes, and addresses to show how array decay works and how it differs from a pointer to an array.
Requirements
- Create an integer array with at least 4 elements.
- Store the decayed array in an
int*pointer. - Store the whole array address in a pointer-to-array variable.
- Print the first and second elements using all three forms.
- Show the difference between
sizeof(arr)andsizeof(pointer). - Demonstrate how
p + 1andq + 1represent different pointer movements.
Keep learning
Related questions
Building More Fault-Tolerant Embedded C++ Applications for Radiation-Prone ARM Systems
Learn practical C++ and compile-time techniques to reduce soft-error damage in embedded ARM systems exposed to radiation.
C Pointer to Array vs Array of Pointers: How to Read Complex Declarations
Learn the difference between pointer-to-array and array-of-pointers in C, plus a simple rule for reading complex declarations correctly.
C printf Format Specifier for bool: How to Print Boolean Values
Learn how to print bool values in C with printf, why no %b/%B specifier exists, and the common patterns to print true/false or 0/1.