Re: question about pointer define



"Wonder" <sapience@xxxxxxxxx> writes:
> Irrwahn Grausewitz <irrwahn35@xxxxxxxxxx> writes:
[attribution added]
>> p p is ...
>> (*p) ... a pointer ...
>> (*p)[3] ... to an array of three ...
>> int (*p)[3] ... ints.
>
> Thanks a lot! Your method is very useful.
>
>>In other words: if you post code here, make sure it's C.
> I rewrite the program in pure C, here it is:
>
> #include <stdio.h>
> int main()
> {
> int (*p)[3];
> /* printf("%x\t%x\t%x\n",*p[0],*p[1],*p[2]); */
> printf("%x\t%x\t%x\n",p[0],p[1],p[2]);
> printf("%x\t%x\t%x\n",&p[0],&p[1],&p[2]);
> }
>
> And I recompiled it by gcc under cygwin. The output is:
> 4 10 1c
> 4 10 1c
>
> The first printf would cause core dump, but now I can understand it if
> here p is a pointer to an int array which has 3 elements.
> My question is why the second and third printf give the same result,
> seems p[i] is same as &p[i] here.

Let's try a modified version of your program.

#include <stdio.h>
#include <stdlib.h>
int main()
{
int (*p)[3];
p = malloc(sizeof *p);
if (p == NULL) {
exit(EXIT_FAILURE);
}
printf("p[0] = %p\n", (void*)p[0]);
printf("&p[0] = %p\n", (void*)&p[0]);
free(p);
return 0;
}

On one implementation, I get:

p[0] = 0x460210
&p[0] = 0x460210

As we've established, p is a pointer to an array of 3 ints.

You didn't initialize p, so its value is garbage. Any attempt to look
at whatever it points to invokes undefined behavior (I got a segmentation
fault). I've corrected this with the malloc() call.

The correct format for printing a pointer value is "%p", not "%x".
The "%p" format expects an argument of type void*; the casts are
necessary (even though you may be able to get away without them).

The prefix to an indexing operator [] is actually a pointer. If it's
the name of an array, as in
int arr[10];
arr[5];
the array name is implicitly converted to a pointer to its first
element. Since p is already a pointer, no such conversion is
necessary.

Remember that, by definition, x[y] is equivalent to *(x+y). In this
case, p[0] is equivalent to *(p+0), which is equivalent to *p. So the
expression p[0] gives you the thing that p points to, which happens to
be an array of 3 ints.

So p[0] is an array of 3 ints. In most contexts, an expression of
array type is implicitly converted to a pointer to its first element.
So in the printf() statement, p[0] is converted to a pointer-to-int,
and its value happens to be 0x460210. (Actually, it's pseudo-random
garbage, but we'll leave that aside for now.)

Note that we considered this conversion rule in two different
contexts. For p, the prefix to the indexing operator, the rule
doesn't apply, because p is already a pointer (to an array of 3 ints).
For p[0], an array of 3 ints, the rule does apply, and it's converted
to a pointer-to-int.

In the second printf, we apply the "&" (address-of) operator to p[0].
This is one of the contexts in which the conversion to pointer
*doesn't* take place. (Another is the operand of the sizeof
operator.) So &p[0] is the address of an array-of-3-ints. p[0] and
&p[0] have different types, but they yield the same raw pointer value
when converted to void* and printed with "%p".

And in your original program, p[1] actually refers to *another* array
of 3 ints, the second element of the array of arrays-of-3-ints to
which p points. In my version of your program, I only allocated
enough memory for a single array-of-3-ints; if I wanted to play with
p[1], I'd have to allocate more memory.

This all seems confusing because, frankly, it is. I went down a
couple of blind alleys while writing this, and I'm not at all certain
that there are no errors in what I've written.

There really aren't many cases where it makes sense to have a pointer
to an array of 3 ints. Usually it makes much more sense to have a
pointer to int, which can be used to access an array of ints. If you
really need an array of items, where each item contains 3 ints, you
might be better off wrapping the array-of-3-ints in a struct and
declaring a pointer to the struct type. Even if you can keep the
complications of a pointer-to-fixed-size-array-of-whatever straight in
your head, the next person to read your code may not be able to.

For a better general understanding of the relationship between arrays
and pointers, read section 6 of the C FAQ,
<http://www.eskimo.com/~scs/C-faq/faq.html>. (In fact, read the whole
thing if you haven't already.)

And before assuming that everything I've written here is correct, wait
a while until the other regulars have had a chance to pick it apart.

--
Keith Thompson (The_Other_Keith) kst-u@xxxxxxx <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
.



Relevant Pages

  • Re: multi dimensional arrays as one dimension array
    ... please - where does the standard say that such a conversion ... Pointer conversion yields a pointer to the same object as ... exist only where there are array declarations. ...
    (comp.lang.c)
  • Re: A base conversion~ help me to correct it since it cant run
    ... An array name is a pointer to the first element of the array. ... Specify a length argument along with scanf for string input. ... To print a pointer value use the p conversion ...
    (comp.lang.c)
  • Re: Wording glitch: sizeof array vs. sizeof (array)
    ... so it's implicitly converted to a pointer. ... That type is an array type, ... the unparenthesized expression "array" is subject to the conversion, ... because it's not an operand of sizeof. ...
    (comp.std.c)
  • Re: question about pointer define
    ... because p is already a pointer (to an array of 3 ints). ... >> This is one of the contexts in which the conversion to pointer ...
    (comp.lang.c)
  • Re: multi dimensional arrays as one dimension array
    ... And so must 'a', or any other pointer ... to access parts of an array that are not accessible via the double *? ... The special characteristic of unsigned char* is that 6.2.6.1p4 defines C's object model, for non-character types with a size of 'n' bytes, in terms of treating them as arrays of n unsigned chars - such an array is defined as constituting the _object representation_ of such types. ... The bounds-checking information cannot be used if the current pointer type is "unsigned char*", and it's meaningless if the current pointer type "void*", but it can still reside inside such pointers, hidden, waiting for conversion to a type which does permit run-time bounds-checking. ...
    (comp.lang.c)