a[1][2] is expanded by compiler like this: *( *(a+1) +2 ). So if a has such a prototype:int **a,
The foregoing expression should be explained like this:
-
Get the address of
afrom symbol table. Note it isapointer
to a pointer -
Now we add it by
1, then it point to the somewhere next to
whereapoint to. -
Then we dereference it. I think here is a undefined behavior,
for we don’t know ifa+1is valid and we arbitraryly access it. -
Ok, if we are lucky enough that we successfully get the value
*(a+1). We add this by2. -
Upon this step, we dereference
(*(a+1) +2 ). Will we be lucky now?
I read this in Expert C Programming in Chapter 10. Is this correct?
New answer, after edited question:
For
a[1][2]to be valid, given thatahas is defined asint **a;, both of these must be true:amust point at the first of two sequentialint *objects;int *objects must point at the first of three sequentialintobjects.The simplest way to arrange this is:
Original answer:
If the expression
a[1][2]is valid, then there are many distinct possibilities for the type ofa(even neglecting qualifiers likeconst):type **a;(pointer to pointer to type)type *a[n];(array of n pointers to type)type (*a)[n];(pointer to array of n type)type a[m][n];(array of m arrays of n type)Precisely how the expression is evaluated depends on which of these types
aactually has.First
a + 1is calculated. Ifais itself a pointer (either case 1 or case 3), then the value ofais directly loaded. Ifais an array (case 2 or case 4), then the address of the first element ofais loaded (which is identical to the address ofaitself).This pointer is now offset by 1 object of the type that it points to. In case 1 and case 2, it would be offset by 1 “pointer to type” object; in case 3 and case 4, it would be offset by 1 “array of n type” object, which is the same as ofsetting by n type objects.
The calculated (offset) pointer is now dereferenced. In cases 1 and 2, the result has type “pointer to type“, in cases 3 and 4 the result has type “array of n type“.
Next
*(a + 1) + 2is calculated. As in the first case, if*(a + 1)is a pointer, then the value is used directly (this time, cases 1 and 2). If*(a + 1)is an array (cases 3 and 4), then the address of the first element of that array is taken.The resulting pointer (which, at this point, always has type “pointer to type“) is now offset by 2 type objects. The final offset pointer is now dereferenced, and the type object is retrieved.