What's the difference among array, &array and &array[0] in C language?
Categories:
Understanding C Arrays: array, &array, and &array[0]
![Hero image for What's the difference among array, &array and &array[0] in C language?](/img/be940b53-hero.webp)
Demystify the subtle yet crucial differences between an array name, its address, and the address of its first element in C programming.
In C programming, arrays are fundamental data structures. However, their interaction with pointers, especially when it comes to their addresses, can be a source of confusion for many developers. This article aims to clarify the distinctions between array
, &array
, and &array[0]
, explaining what each expression evaluates to and how they behave in different contexts.
The Array Name: array
When you declare an array in C, the array's name itself acts as a constant pointer to its first element. This means that in most expressions, array
decays into a pointer to its first element. Its type is 'pointer to element type'. For an array int arr[5];
, arr
evaluates to the address of arr[0]
, and its type is int *
.
int arr[5] = {10, 20, 30, 40, 50};
printf("Value of arr: %p\n", (void*)arr); // Address of the first element
printf("Type of arr: %s\n", "int *"); // Conceptual type
printf("Value of &arr[0]: %p\n", (void*)&arr[0]); // Same address as arr
printf("Type of &arr[0]: %s\n", "int *"); // Conceptual type
Demonstrating the value and conceptual type of arr
and &arr[0]
.
Address of the Array: &array
While array
points to the first element, &array
refers to the address of the entire array object. The key difference here is the type. For int arr[5];
, &arr
has the type int (*)[5]
, which means 'pointer to an array of 5 integers'. Although its value (the memory address) is the same as arr
and &arr[0]
, its type carries information about the size of the entire array. This type difference becomes significant in pointer arithmetic.
int arr[5] = {10, 20, 30, 40, 50};
printf("Value of &arr: %p\n", (void*)&arr); // Address of the entire array
printf("Type of &arr: %s\n", "int (*)[5]"); // Conceptual type
// Pointer arithmetic difference:
printf("arr + 1: %p\n", (void*)(arr + 1)); // Moves by sizeof(int) (4 bytes)
printf("&arr + 1: %p\n", (void*)(&arr + 1)); // Moves by sizeof(arr) (5 * 4 = 20 bytes)
Illustrating the type and pointer arithmetic behavior of &arr
.
flowchart TD subgraph Memory Layout A[arr[0]] B[arr[1]] C[arr[2]] D[arr[3]] E[arr[4]] end arr -- points to --> A "&arr[0]" -- points to --> A "&arr" -- points to --> A style A fill:#f9f,stroke:#333,stroke-width:2px style B fill:#fff,stroke:#333,stroke-width:1px style C fill:#fff,stroke:#333,stroke-width:1px style D fill:#fff,stroke:#333,stroke-width:1px style E fill:#fff,stroke:#333,stroke-width:1px subgraph Pointer Types P1["arr (int *)"] P2["&arr[0] (int *)"] P3["&arr (int (*)[5])"] end P1 --> arr P2 --> "&arr[0]" P3 --> "&arr"
Visual representation of arr
, &arr[0]
, and &arr
pointing to the same starting memory address but having different types.
Address of the First Element: &array[0]
This expression explicitly takes the address of the first element of the array. It is the most straightforward way to get a pointer to the first element. Its type is 'pointer to element type', which for int arr[5];
is int *
. As seen, its value is identical to arr
.
arr
and &arr[0]
yield the same address and have the same type (int *
for int arr[5]
), using &arr[0]
can sometimes improve code clarity by explicitly stating that you are taking the address of an element, rather than relying on array-to-pointer decay.Summary of Differences
The core difference lies in their types and how those types influence pointer arithmetic and type checking. All three expressions evaluate to the same memory address, which is the starting address of the array. However, their types dictate how the compiler interprets operations like + 1
.
flowchart LR A["int arr[5]"] B["arr"] C["&arr[0]"] D["&arr"] B -- "Decays to" --> E["Pointer to first element (int *)"] C -- "Explicitly is" --> E D -- "Is" --> F["Pointer to entire array (int (*)[5])"] E -- "Value: Start Address" --> G[Memory Address] F -- "Value: Start Address" --> G E -- "Pointer Arithmetic: Moves by sizeof(int)" --> H[Next int address] F -- "Pointer Arithmetic: Moves by sizeof(arr)" --> I[Next array address] style G fill:#f9f,stroke:#333,stroke-width:2px style E fill:#ccf,stroke:#333,stroke-width:1px style F fill:#ccf,stroke:#333,stroke-width:1px
Conceptual differences between arr
, &arr[0]
, and &arr
.
Understanding these distinctions is crucial for writing correct and efficient C code, especially when dealing with functions that accept array arguments or when performing complex pointer manipulations.