What's the difference among array, &array and &array[0] in C language?
Categories:
Understanding C Arrays: array, &array, and &array[0]

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:1pxConceptual 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.