Understanding Array Decay to Pointers in C Language (Part 1)

Array Decay RulesIn 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.Understanding Array Decay to Pointers in C Language (Part 1)

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) { ... }

Understanding Array Decay to Pointers in C Language (Part 1)

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));
}
Understanding Array Decay to Pointers in C Language (Part 1)Understanding Array Decay to Pointers in C Language (Part 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}

Understanding Array Decay to Pointers in C Language (Part 1)Understanding Array Decay to Pointers in C Language (Part 1)

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

Understanding Array Decay to Pointers in C Language (Part 1)

  • Summary
  1. 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..

Understanding Array Decay to Pointers in C Language (Part 1) “ Your support is my greatest motivation ”

Leave a Comment