Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Will the prototype of a[1][2] be this: int **a?

Tags:

c

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:

  1. Get the address of a from symbol table. Note it is a pointer to a pointer

  2. Now we add it by 1, then it point to the somewhere next to where a point to.

  3. Then we dereference it. I think here is a undefined behavior, for we don't know if a+1 is valid and we arbitraryly access it.

  4. Ok, if we are lucky enough that we successfully get the value *(a+1). We add this by 2.

  5. 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?

like image 730
larmbr Avatar asked Feb 01 '26 22:02

larmbr


1 Answers

New answer, after edited question:

For a[1][2] to be valid, given that a has is defined as int **a;, both of these must be true:

  • a must point at the first of two sequential int * objects;
  • The second of those int * objects must point at the first of three sequential int objects.

The simplest way to arrange this is:

int x[3];
int *y[2] = { 0, x };
int **a = y;

Original answer:

If the expression a[1][2] is valid, then there are many distinct possibilities for the type of a (even neglecting qualifiers like const):

  1. type **a; (pointer to pointer to type)
  2. type *a[n]; (array of n pointers to type)
  3. type (*a)[n]; (pointer to array of n type)
  4. type a[m][n]; (array of m arrays of n type)

Precisely how the expression is evaluated depends on which of these types a actually has.

First a + 1 is calculated. If a is itself a pointer (either case 1 or case 3), then the value of a is directly loaded. If a is an array (case 2 or case 4), then the address of the first element of a is loaded (which is identical to the address of a itself).

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) + 2 is 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.

like image 56
caf Avatar answered Feb 04 '26 16:02

caf



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!