In C programming, understanding how arrays and pointers relate is fundamental for efficient and bug-free coding. Among the most common points of confusion are the distinctions between array, &array, and &array[0]. This article explores these concepts deeply, with illustrative examples, memory insights, and diagrams to clarify their differences and practical usage.

Introduction to Arrays, &array, and &array[0]

An array in C is a collection of elements of the same data type stored contiguously in memory. However, there are subtle differences when you use the array name alone, its address &array, or the address of its first element &array[0]. These expressions may appear similar but have distinct meanings and types in the context of C pointers and memory.

Understanding array, &array, and &array[0] Basics

Consider this example declaration:

int arr[5] = {10, 20, 30, 40, 50};
  • arr: Refers to the address of the first element of the array, which can be used as a pointer to int.
  • &arr: Refers to the address of the entire array, which is a pointer to an array of 5 integers int (*)[5].
  • &arr[0]: Specifically, the address of the first element, same as arr, type int *.

Though arr and &arr[0] point to the same memory location, their types differ from &arr, which points to the whole array object.

Memory Layout & Pointer Behavior Example

Here is a simple C program and its output to visualize the differences:

#include <stdio.h>

int main() {
    int arr[5] = {10, 20, 30, 40, 50};
    
    printf("arr = %p\n", (void*)arr);
    printf("&arr = %p\n", (void*)&arr);
    printf("&arr[0] = %p\n", (void*)&arr[0]);
    
    printf("sizeof(arr) = %zu bytes\n", sizeof(arr));
    printf("sizeof(&arr) = %zu bytes\n", sizeof(&arr));
    printf("sizeof(&arr[0]) = %zu bytes\n", sizeof(&arr[0]));

    return 0;
}

Expected Output:

arr = 0x7ffee2b8e650
&arr = 0x7ffee2b8e650
&arr[0] = 0x7ffee2b8e650
sizeof(arr) = 20 bytes
sizeof(&arr) = 8 bytes
sizeof(&arr[0]) = 8 bytes

arr, &arr, and &arr[0] hold the same address but represent different pointer types and sizes. arr or &arr[0] is a pointer to int, while &arr is a pointer to the entire array of 5 ints, showing why sizeof(arr) is 20 bytes (5 * 4 bytes) but sizeof(&arr) is only the size of a pointer (8 bytes on 64-bit systems).

Type Differences and Pointer Arithmetic

The primary difference lies in pointer arithmetic, as the types determine how pointer increments behave:

  • arr + 1 advances by sizeof(int) bytes (usually 4 bytes), pointing to arr[1].
  • &arr + 1 advances by sizeof(int[5]) bytes (usually 20 bytes), pointing just after the entire array.
  • &arr[0] + 1 behaves the same as arr + 1.

Practical Uses and Considerations

  • Use arr or &arr[0] when you want a pointer to the first element for iteration or array element access.
  • Use &arr when you want to pass the entire array as a single pointer or emphasize the array boundary, especially with multidimensional arrays or when precise array sizes are required.
  • Functions receiving arrays typically use int *arr, so passing arr or &arr[0] is common and expected.
  • Using &arr as a pointer requires careful handling because its type is different and pointer arithmetic behaves differently.

Example: Function Parameters Differentiation

void func1(int *p) {
    printf("%d\n", p[1]);  // Access second element
}

void func2(int (*p)[5]) {
    printf("%d\n", (*p)[1]); // Access second element of the whole array pointer
}

int main() {
    int arr[5] = {1, 2, 3, 4, 5};
    
    func1(arr);          // arr decays to int*
    func1(&arr[0]);      // Equivalent to arr
    
    func2(&arr);         // Passing pointer to entire array
    
    return 0;
}

Summary Table of Differences

Expression Type Points To Pointer Arithmetic Typical Use
arr int * First element arr[0] Advances by one element (int) Access elements, pass array to functions
&arr int (*)[5] Whole array arr (all 5 elements) Advances by whole array size (5 * int) Manipulate entire array as one block
&arr[0] int * First element arr[0] Advances by one element (int) Same as arr, pointer to first element

Conclusion

Understanding the difference between array, &array, and &array[0] in C is crucial for pointer operations, memory management, and function interfaces. While array and &array[0] often can be used interchangeably as pointers to the first element, &array carries the full array type and size information, affecting pointer arithmetic and type safety. Using these correctly leads to clearer, safer, and more efficient C code.