Array Decay Rules:In most cases, the name of an array is implicitly converted (or referred to as “decay”) to a pointer to its first element. This behavior is specified by the language standard.★
1. Cases Where Arrays Convert to Pointers
1.1 Array Name as Function Parameter
When an array is passed as a function parameter, it is converted to a pointer to its first element.
What the function receives is a pointer, not a copy of the entire array. This conversion is to improve efficiency,avoiding the overhead of passing the entire array.
#include <stdio.h>// Function declaration, parameter is actually a pointer int* void printArray(int arr[], int size); // Here int arr[] is equivalent to int* arr // A more idiomatic way is actually void printArray(int* arr, int size);int main() { int myArray[5] = {1, 2, 3, 4, 5}; // Passing myArray, it will be converted to &myArray[0] (an int* type) printArray(myArray, 5); return 0;}// Function definitionvoid printArray(int arr[], int size) // arr is a pointer here{ for (int i = 0; i < size; i++) { printf("%d ", arr[i]); // Even if arr is a pointer, subscript syntax can still be used printf("%d ", *(arr + i)); // This is equivalent to the previous line }}
1.2 Array Name Used on the Right Side of Assignment Statements
- When using the array name for assignment or initialization, it decays to a pointer.
int arr[5] = {1, 2, 3, 4, 5};int* ptr = arr; // Correct: 'arr' decays to &arr[0], type is int* // int* ptr = &arr[0]; // This is completely equivalent to the previous line
1.3 Array Name Participating in Arithmetic Operations
- When performing operations like +, -, ++, — on the array name, the object being operated on is a pointer.
int arr[5] = {1, 2, 3, 4, 5};int* ptr1 = arr + 1; // ptr1 points to arr[1] (the 2nd element, 2)int* ptr2 = arr + 3; // ptr2 points to arr[3] (the 4th element, 4)// Commonly used for traversalint* end = arr + 5; // Points to the "end of the array", commonly used for loop termination conditionfor (int* p = arr; p < end; p++) { printf("%d", *p);}
1.4 Array Name Used with the Subscript Operator []
- The expression arr[i] is interpreted by the compiler as *(arr + i).
int value = arr[2];// The compiler processes it as:// 1. Get the address of the first element &arr[0] (i.e., the decayed value of arr)// 2. Add an offset of 2 * sizeof(int) to get the address of &arr[2]// 3. Dereference that address: *(&arr[2])
1.5 Array Name Used with Relational Operators
- When using relational operators like ==, !=, <, >, etc., the array name also decays to a pointer.
int arr1[5], arr2[5];int* ptr = arr1;if (ptr == arr1) // Comparing whether the address values of the two pointers are equal{ printf("ptr points to the start of arr1.\n");}// This compares the addresses of two arrays, which usually has no meaning, the compiler may warn// if (arr1 == arr2) { ... }

2. Cases Where Array Names Do Not Convert to Pointers
2.1 As an Operand of the sizeof Operator
sizeof(arr) returns the total number of bytes occupied by the entire array (e.g., 5 * sizeof(int)), not the size of a pointer (like 4 or 8 bytes).
#include <stdio.h>int main() { int arr[5] = {1, 2, 3, 4, 5}; int* ptr = arr; // 5 ints × 4 bytes = 20 bytes printf("Size of entire array: %zu bytes\n", sizeof(arr)); // Pointer size is 8 bytes on a 64-bit system printf("Size of a pointer: %zu bytes\n", sizeof(ptr)); // Size of int: 4 bytes printf("Size of int: %zu bytes\n", sizeof(int));
// A common way to get the number of elements in the array size_t element_count = sizeof(arr) / sizeof(arr[0]); printf("Number of elements in array: %zu\n", element_count);
}
2.2 As an Operand of the Address-of Operator &
<span> When using & on an array name, it yields a "pointer to the entire array", not "a pointer to the first element".</span><span> For example </span><span>int (*)[5]</span> instead of <span>int*</span>. Its value is the same as <span>&arr[0]</span><span>, but the types are different, and pointer arithmetic behaves differently (</span><code><span>&arr + 1</span><span> will skip the entire array).</span><pre><code class="language-c">#include <stdio.h>int main() { int arr[5] = {10, 20, 30, 40, 50};
printf("arr: %p\n", (void*)arr); printf("&arr[0]: %p\n", (void*)&arr[0]); printf("&arr: %p\n", (void*)&arr);
// Although the values are the same, the types are different! int* ptr_to_first = arr; // int* int (*ptr_to_whole_array)[5] = &arr; // int (*)[5]
// printf("%p (moves by sizeof(int)=4 bytes)\n", (void*)(ptr_to_first + 1)); printf("%p (moves by sizeof(int[5])=20 bytes)\n", (void*)(ptr_to_whole_array + 1));
}

Key Points:
-
All three address values are the same, pointing to the same location in memory.
-
But the types are completely different:
-
<span>arr</span>and<span>&arr[0]</span>have the type<span>int*</span> -
<span>&arr</span>has the type<span>int (*)[5]</span>(a pointer to an array containing 5 ints) -
Pointer arithmetic shows significant differences:
-
<span>int* + 1</span>advances by<span>sizeof(int)</span>bytes -
<span>int (*)[5] + 1</span>advances by<span>sizeof(int[5])</span>bytes (the size of the entire array)
2.3 As a String Literal Initializing a Character Array
char str[] = "Hello";
Here, <span>"Hello"</span> is an array initializer, and <span>str</span> itself does not decay.
#include <stdio.h>int main() { // Initializing character array - does not decay char str1[] = "Hello"; // Array size is 6 (including null terminator) char str2[10] = "World";
// This is different from pointer initialization char* ptr = "Hello"; // ptr is a pointer, pointing to a string constant
printf("sizeof(str1): %zu (entire array)\n", sizeof(str1)); printf("sizeof(ptr): %zu (pointer size)\n", sizeof(ptr));
// str1 is an array, can modify content (on the stack) str1[0] = 'h'; printf("Modified str1: %s\n", str1);
// ptr points to a constant string, modifying it will lead to undefined behavior // ptr[0] = 'w'; // Dangerous! May crash}


2.4 As an Operand of _Alignof (C11 Standard)
#include <stdio.h>#include <stdalign.h>int main() { int arr[5]; int* ptr = arr;
printf("Alignment of array: %zu\n", _Alignof(arr)); printf("Alignment of pointer: %zu\n", _Alignof(ptr)); printf("Alignment of int: %zu\n", _Alignof(int));
}
-
The C11 standard is still widely used
-
MSVC (Visual Studio): Limited support for C11, but some C11 features can be used with specific settings

- Summary
- Except for the three cases where the array name is used as an operand of
<span><span>sizeof</span></span>,<span><span>&</span></span>and string initializers, the array name will automatically convert to a pointer to its first element in all other expressions..
“ Your support is my greatest motivation ”