void g()
{
int a[3][2] = {{1,2},{3,4},{5,6}};
printf("%d\n", *(a[2]-1));
}
I need to figure out the output of the function (written in c)
I expected it may fail or print some random stuff, because a[2] is a pointer to an array, and a[2]-1 will point to some random area in the memory. However, the answer is that it prints 4
- I can not figure about why it does that. Any ideas?
C evaluates *(a[2]-1)
:
a
is not the operand of sizeof
, the operand of unary &
, or a string literal used to initialize an array, it is automatically converted to a pointer to its first element. As a
is an array of 3 arrays of 2 int
, its first element is an array of 2 int
, which we usually think of as a[0]
. So the conversion to a pointer to this yields &a[0]
.a[2]
, the subscript operator is defined to add the integer to the pointer and then apply *
, as if we had written * (&a[0] + 2)
. Adding 2 to &a[0]
produces a pointer to two elements further in the array a
, namely the element a[2]
, so the produced pointer is &a[2]
. Then applying *
yields a[2]
. (Yes, this is the same thing we started with in this step—I am showing the semantics as specified by the C standard and that they produce the result we intuitively think of.)a[2]-1
, a[2]
is an array (it is an array of 2 int
), and it is not the operand of sizeof
, the operand of unary &
, or a string literal used to initialize an array. So it is automatically converted to a pointer to its first element. We usually think of its first element as a[2][0]
, so the pointer is &a[2][0]
.-
, we subtract 1 from the pointer &a[2][0]
. This points to an element back one element in the array a[2]
.At this point, we have a problem. Subtracting one from &a[2][0]
would produce &a[2][-1]
, but that is outside the bounds of a[2]
. We know the element prior to a[2][0]
in memory is a[1][1]
, because arrays (and their subarrays) are laid out in memory contiguously. And thus, when we apply *
to this pointer, a C implementation will often produce the value of a[1][1]
, which is 4.
However, pointer arithmetic is not defined by the C standard when it goes out of bounds of the array the initial pointer points to. Those bounds are the starting element of the array and a position just beyond the last element. For a[2]
, the bounds are from &a[2][0]
(its start element) to &a[2][2]
(one beyond its last element, a[2]][1]
). &a[2][-1]
is not in those bounds.
Some C implementations may support crossing subarray boundaries within a larger array. However, it is also possible that an optimizer in the compiler handles such a crossing differently and produces a different result.