f



More on pointers to pointers.

I suspect I'm missing a broader concept here. Okay, given the following
code:

#include <stdio.h>

int main(void) {
    char *ptr[] = {"Garbage", "test", "work"};
    char **arg;

    arg = ptr;

    printf("The string is: %s\n", ptr[1]);
    return 0;
}

Why am I not allowed to do something like:
arg = &ptr; ?

I guess even more to the point, why is this legal?
arg = &(*ptr) ;

Chad

0
cdalten (975)
3/31/2006 2:43:27 AM
comp.lang.c 30657 articles. 5 followers. spinoza1111 (3246) is leader. Post Follow

6 Replies
601 Views

Similar Articles

[PageSpeed] 33

Chad said:

> I suspect I'm missing a broader concept here. Okay, given the following
> code:
> 
> #include <stdio.h>
> 
> int main(void) {
>     char *ptr[] = {"Garbage", "test", "work"};
>     char **arg;
> 
>     arg = ptr;
> 
>     printf("The string is: %s\n", ptr[1]);
>     return 0;
> }
> 
> Why am I not allowed to do something like:
> arg = &ptr; ?

Because &ptr has the wrong type. ptr has the type "array of three pointers 
to char", so &ptr would have the type "pointer to array of three pointers 
to char", whereas arg is not of this type or a compatible type.

> I guess even more to the point, why is this legal?
> arg = &(*ptr) ;

& and * cancel.

-- 
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
0
invalid171 (7008)
3/31/2006 3:04:01 AM
In article <1143773007.173184.158940@u72g2000cwu.googlegroups.com>,
Chad <cdalten@gmail.com> wrote:
>I suspect I'm missing a broader concept here.

It looks to me like the broader concept you're missing is actually
pointers and arrays, not pointers to pointers.
You may find further enlightenment at
http://www.c-faq.com/aryptr/index.html
and at
http://groups.google.com/groups?q=group:comp.lang.c+author:"chris+torek"+"the+rule"


>     Okay, given the following
>code:
>
>#include <stdio.h>
>
>int main(void) {
>    char *ptr[] = {"Garbage", "test", "work"};

ptr is an array of pointer to char with a slightly confusing name (since
it isn't actually a pointer).
Like any other array, it will be converted to a pointer to its first
element in most places you'll use it.

>    char **arg;

....and arg is a pointer to pointer to char, which can point at any element
of ptr[] (in particular, the first one that you get when you just say
`ptr' in a value context).

>
>    arg = ptr;

This does:
Convert ptr (array of pointer to char) into a pointer to its first
element (with type pointer to pointer to char).
Store that value in arg.

>
>    printf("The string is: %s\n", ptr[1]);
>    return 0;
>}
>
>Why am I not allowed to do something like:
>arg = &ptr; ?

Giving it to the & operator like you're doing here is one of the
places where an array name *doesn't* get converted to a pointer[1].
The right-hand side of this assignment is a pointer to the array (with
type "pointer to array 3 of pointer to char"), and you're trying to
assign it to a pointer to pointer; since there's not a defined way to
convert from one of those types to the other (and not really a sensible
way either), the compiler complains.

>I guess even more to the point, why is this legal?
>arg = &(*ptr) ;

ptr gets converted to a pointer to its first element, and then you follow
that pointer, so the expression inside the parens identifies an object
of type pointer to char.
Then the & operator gives you a pointer to that object, with type
pointer to pointer to char.  Since this is the same type of the object
you're storing it into, this works with no problems or complaints from
the compiler.

(This one is actually a special case of a more general rule: since & (get
pointer) and * (follow pointer) are inverse operations, saying "&(*p)"
will always give you the same value as just saying "p" for any pointer p,
and "*(&x)" will always give you the same object as just saying "x".)



Note that none of this actually needed us to know that ptr was an array
of pointers - everything would have worked the same way if it were, say,
an array of ints (as long as arg was a pointer the same type that ptr
was an array of).  Pointers to pointers are just like pointers to any
other type: you can dereference a "foo *" to get a value of type "foo",
even if "foo" is a pointer type itself.



dave

[1] The other one you're likely to come across is when it's the operand
    of the sizeof operator.  I'm not going to complain that those are
    the only two places it happens, but they're the only ones I can
    recall ever having come across.

-- 
Dave Vandervies                           dj3vande@csclub.uwaterloo.ca
If parachutes were maintained to the same standards as the typical car
you'd have parachutists dropping out of the skies like flies. 
                                   --Bram in the scary devil monastery
0
dj3vande (669)
3/31/2006 3:14:02 AM
Dave Vandervies wrote:
> In article <1143773007.173184.158940@u72g2000cwu.googlegroups.com>,
> Chad <cdalten@gmail.com> wrote:
> >I suspect I'm missing a broader concept here.
>
> It looks to me like the broader concept you're missing is actually
> pointers and arrays, not pointers to pointers.
> You may find further enlightenment at
> http://www.c-faq.com/aryptr/index.html
> and at
> http://groups.google.com/groups?q=group:comp.lang.c+author:"chris+torek"+"the+rule"
>
>
> >     Okay, given the following
> >code:
> >
> >#include <stdio.h>
> >
> >int main(void) {
> >    char *ptr[] = {"Garbage", "test", "work"};
>
> ptr is an array of pointer to char with a slightly confusing name (since
> it isn't actually a pointer).
> Like any other array, it will be converted to a pointer to its first
> element in most places you'll use it.
>
> >    char **arg;
>
> ...and arg is a pointer to pointer to char, which can point at any element
> of ptr[] (in particular, the first one that you get when you just say
> `ptr' in a value context).
>
> >
> >    arg = ptr;
>
> This does:
> Convert ptr (array of pointer to char) into a pointer to its first
> element (with type pointer to pointer to char).
> Store that value in arg.
>
> >
> >    printf("The string is: %s\n", ptr[1]);
> >    return 0;
> >}
> >
> >Why am I not allowed to do something like:
> >arg = &ptr; ?
>
> Giving it to the & operator like you're doing here is one of the
> places where an array name *doesn't* get converted to a pointer[1].
> The right-hand side of this assignment is a pointer to the array (with
> type "pointer to array 3 of pointer to char"), and you're trying to
> assign it to a pointer to pointer; since there's not a defined way to
> convert from one of those types to the other (and not really a sensible
> way either), the compiler complains.
>

So in other words,
args = ptr;

could also be written as
args = &ptr[0]; ?

Chad

0
cdalten (975)
3/31/2006 4:36:38 AM
Dave Vandervies wrote:
> In article <1143773007.173184.158940@u72g2000cwu.googlegroups.com>,
> Chad <cdalten@gmail.com> wrote:
<snip>
>> I guess even more to the point, why is this legal?
>> arg = &(*ptr) ;
> 
> ptr gets converted to a pointer to its first element, and then you follow
> that pointer, so the expression inside the parens identifies an object
> of type pointer to char.
> Then the & operator gives you a pointer to that object, with type
> pointer to pointer to char.  Since this is the same type of the object
> you're storing it into, this works with no problems or complaints from
> the compiler.
> 
> (This one is actually a special case of a more general rule: since & (get
> pointer) and * (follow pointer) are inverse operations, saying "&(*p)"
> will always give you the same value as just saying "p" for any pointer p,
> and "*(&x)" will always give you the same object as just saying "x".)
> 
To be precise in a way that doesn't really matter but is still notable: this 
is a direct consequence of how & is defined. In particular, the standard 
guarantees that "&*p" is equivalent to "p" for *any* pointer p, even if p is 
invalid, because the subexpression "*p" is not evaluated.

Some compilers actually get this wrong if optimization is not turned on, and 
will insert evaluation of the pointer.

S.
0
invalid58 (621)
3/31/2006 6:40:27 PM
Skarmander wrote:
> Dave Vandervies wrote:
>> In article <1143773007.173184.158940@u72g2000cwu.googlegroups.com>,
>> Chad <cdalten@gmail.com> wrote:
> <snip>
>>> I guess even more to the point, why is this legal?
>>> arg = &(*ptr) ;
>>
>> ptr gets converted to a pointer to its first element, and then you follow
>> that pointer, so the expression inside the parens identifies an object
>> of type pointer to char.
>> Then the & operator gives you a pointer to that object, with type
>> pointer to pointer to char.  Since this is the same type of the object
>> you're storing it into, this works with no problems or complaints from
>> the compiler.
>>
>> (This one is actually a special case of a more general rule: since & (get
>> pointer) and * (follow pointer) are inverse operations, saying "&(*p)"
>> will always give you the same value as just saying "p" for any pointer p,
>> and "*(&x)" will always give you the same object as just saying "x".)
>>
> To be precise in a way that doesn't really matter but is still notable: 
> this is a direct consequence of how & is defined. In particular, the 
> standard guarantees that "&*p" is equivalent to "p" for *any* pointer p, 
> even if p is invalid, because the subexpression "*p" is not evaluated.
> 
> Some compilers actually get this wrong if optimization is not turned on, 
> and will insert evaluation of the pointer.
> 
Evaluation of the indirection, obviously.

S.
0
invalid58 (621)
3/31/2006 6:45:48 PM
In article <1143779798.922469.30560@v46g2000cwv.googlegroups.com>,
Chad <cdalten@gmail.com> wrote:
>
>Dave Vandervies wrote:

>> ptr is an array of pointer to char with a slightly confusing name (since
>> it isn't actually a pointer).
>> Like any other array, it will be converted to a pointer to its first
>> element in most places you'll use it.

[much snippage]

>So in other words,
>args = ptr;
>
>could also be written as
>args = &ptr[0]; ?

Yes.
In the case of an array, the second version makes explicit what's being
done implicitly in the first version[1].

Somewhat confusingly (at least while you're still working on wrapping
your brain around it - once you Get It, it all makes perfect sense), even
if ptr were actually a pointer and not an array, these would still be
equivalent, since array indexing is defined in terms of pointer addition:
    ptr[index]
is exactly equivalent to
    *(ptr+index)
for any pointer (or array) ptr.
(And, of course, indexing with a pointer to a vector of objects works
the same way as indexing an array of objects.)

If you really want confusing, since pointer addition is commutative,
ptr[index] and *(ptr+index) are also equivalent to
    *(index+ptr)
and therefore to
    index[ptr]
- go ahead and try it out (just don't write serious code that uses this).


dave

[1] Actually, to be pedantically correct, it's doing something different-
    but-with-identical-observable-effects.  ptr is still being converted
    from an array to a pointer to its first element, then indexing it
    with [0] gives you that element, and then applying & gives you a
    pointer to that element.

-- 
Dave Vandervies                        dj3vande@csclub.uwaterloo.ca
It is two statements.  If enclosed by {} it would be one statement,
which happens to be compound, and to consist of two statements.
                                        --CBFalconer in comp.lang.c
0
dj3vande (669)
4/1/2006 4:21:34 AM
Reply: