In C, is it guaranteed that the array start address is smaller than the other elements' addresses?

The address ordering is guaranteed. The behaviour of relational operators is defined in C11 6.5.8p5:

[...] pointers to array elements with larger subscript values compare greater than pointers to elements of the same array with lower subscript values. [...]

Thus &array[x] >= &array[0] is true always if x is the index of an element, or one greater than the maximum index. (And if x is not the index of an element, or one past the end of the actual array, then behaviour is undefined.)

But surprisingly the difference &array[x] - &array[0] is defined only when

  • x is an actual index of an element or one greater than the maximum index in the array and
  • x is not greater than PTRDIFF_MAX

as there is a peculiar corner case: C11 6.5.6p9 says that

9 When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements. The size of the result is implementation-defined, and its type (a signed integer type) is ptrdiff_t defined in the <stddef.h> header. If the result is not representable in an object of that type, the behavior is undefined. In other words, if the expressions P and Q point to, respectively, the i-th and j-th elements of an array object, the expression (P)-(Q) has the value i-j provided the value fits in an object of type ptrdiff_t.[...]

If the signed ptrdiff_t is of same width as the unsigned size_t, it is possible to have an array for which there exists an index x greater than PTRDIFF_MAX; then &array[x] >= &array[0] still, but &array[x] - &array[0] has completely undefined behaviour.


Here is a demonstration. My computer is x86-64 that runs 64-bit Ubuntu Linux, but it is also capable of running 32-bit programs. In 32-bit X86 Linux + GCC, ptrdiff_t is a 32-bit signed integer, and size_t is 32-bit unsigned integer. A program run in 64-bit Linux in 32-bit mode can easily allocate over 2G of memory with malloc, as the entire 4G address space is reserved for user mode.

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <stddef.h>

int main(void) {
    size_t size = (size_t)PTRDIFF_MAX + 2;
    size_t x = (size_t)PTRDIFF_MAX + 1;
    char *array = malloc(size);
    if (! array) {
        perror("malloc");
        exit(1);
    }
    array[0] = 42;
    array[x] = 84;
    printf("&array[0]: %p\n", (void *)&array[0]);
    printf("&array[x]: %p\n", (void *)&array[x]);
    printf("&array[x] >= &array[0]: %d\n", &array[x] >= &array[0]);
    printf("&array[x] - &array[1]: %td\n", &array[x] - &array[1]);
    printf("&array[x] - &array[0]: %td\n", &array[x] - &array[0]);
    printf("(&array[x] - &array[0]) < 0: %d\n", (&array[x] - &array[0]) < 0);
}

Then compiled for 32-bit mode and run:

% gcc huge.c -m32 -Wall && ./a.out 
&array[0]: 0x77567008
&array[x]: 0xf7567008
&array[x] >= &array[0]: 1
&array[x] - &array[1]: 2147483647
&array[x] - &array[0]: -2147483648
(&array[x] - &array[0]) < 0: 1

The memory was allocated successfully, the starting address is at 0x77558008, &array[x] is at 0xf7504008, &array[x] is greater than &array[0]. The difference &array[x] - &array[1] produced a positive result, whereas &array[x] - &array[0], with its undefined behaviour, now produced a negative result!


First of all, FWIW, quoting C11, chapter §6.5.6/P9, (emphsis mine)

When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements. [...]

So, you don't need to be bothered about the individual pointer value (positioning) itself. It's the difference that matters (i.e, something like |a-b|)


That said, if it has to come to the "comparison", ( usage of relational operators, <, >, <=, >=), the standard says,

When two pointers are compared, the result depends on the relative locations in the address space of the objects pointed to. [....] If the objects pointed to are members of the same aggregate object, [...] and pointers to array elements with larger subscript values compare greater than pointers to elements of the same array with lower subscript values. [....]

So, for a statement like &array[x] <= &array[0], it will evaluate to 0 (FALSY), when x > 0.

Thanks to the other answer by Joachim


Yes, because &array[x] is defined to be equivalent to array+x.

6.5.2.1p2:

A postfix expression followed by an expression in square brackets [] is a subscripted designation of an element of an array object. The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2))). Because of the conversion rules that apply to the binary + operator, if E1 is an array object (equivalently, a pointer to the initial element of an array object) and E2 is an integer, E1[E2] designates the E2-th element of E1 (counting from zero).