开发者

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

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?


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.


Let's say the definition of a looks something like this:

int a[2][2] = {{1, 2}, {3, 4}};

Here's what the storage that the symbol a looks like:

[ 1 ][ 2 ][ 3 ][ 4 ]

In C, when you perform arithmetic on a pointer, the actual amount by which the pointer value is incremented or decremented is based on the size of the type stored in the array. The type contained in the first dimension of a is int[2], so when we ask C to calculate the pointer value (a + 1), it takes the location named by a and increments it by the size of int[2], which results in pointer referring to the memory location containing the integer value [3]. So yes, when you dereference this pointer and then add 2 to it, the result is the integer value 5. When you then try to dereference that integer value, it makes no sense.

So now let's say the array contains pointers:

char const * one = "one",
             two = "two",
             three = "three",
             four = "four";
char const * a[2][2] = {{one, two}, {three, four}};

Add 1 to a and then dereference it, and you get the char pointer referring to the string "three." Add two to this, and you'll get a pointer referring to a now shorter string "ree". Dereference that, and you get the char value 'r', but only by sheer luck did you avoid a memory protection fault.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜