[comp.lang.c] Perplexed by pointers

vlcek@mit-caf.MIT.EDU (Jim Vlcek) (11/25/88)

A little note on Carl Paukstis' problems with a (char **) cast and
dereferencing of a (void *) pointer.  Just to refresh your memories, a
brief insert from Doug Gwyn's last posting on the matter:

*In article <2176@iscuva.ISCS.COM> carlp@iscuva.ISCS.COM (Carl
*Paukstis) writes:
*->>86           code = strcmp (key, *(char **)((char *)table + (m * size)));
*->Line 86 is okay, but you really don't need to cast to a (char**) then
*->dereference to get the (char*) key.  That's extra work that amounts to
*->a no-op.
*-  Huh?  The type of the expression ((char *)table + (m * size)) is
*-  "pointer to char", no?  And the usage on line 86 requires "pointer to
*-  pointer to char".  If I dereference the subexpression above, e.g.
*-  *((char *)table + (m * size)), the result type is "char", not "pointer
*-  to char" as required by strcmp().  Or am I just being dense?
*
*That's not what I said!
*
*You already had a (char *).  You then cast it to (char **), and then
*dereferenced that using the * operator.  There was no need for these
*extra steps when the original (char *) was just what you needed.
*(strcmp takes (char *) arguments.)

Carl is in fact completely right on this one, and the way in which he
did the operation is exactly the right way.  Consider:

``table'' is a pointer to an array of structures, each of size
``size'', and whose first element is a pointer to char (char *).  He
needs to pass one of these pointers to strcmp().  Since it is the
pointers which are contained in ``table,'' not the actual strings to
be compared, obviously a dereference needs to be performed to be able
to pass the correct value to strcmp().

Since the routine to which ``table'' is passed has no idea what kind
of structures comprise this array, it is given the size of each
structure as ``size.''  Hence, casting ``table'' to (char *) and
adding m*size to it are perfectly correct; this then yields a pointer
to the m-th array entry (structure-wise) in ``table.''  Since the address
of the first element of any structure is also the address of the
structure itself (suitably cast), this value is then also the address
of the first element in the structure -- this so happens to be a
pointer to char.  Hence, the cast to (char **) is appropriate.  One
then dereferences this to get the actual pointer value, passes it to
strcmp(), and voila!

People here paid too much attention to the pointer types, and not
enough attention to the values!  The original cast to (char *) is only
done to be able to correctly perform the necessary pointer arithmetic,
for in fact ``table'' is in no sense really a pointer to char.  I'm
suprised that the notion of *(char **) amounting to a no-op managed to
breeze by Doug Gwyn!
-- 
Jim Vlcek
vlcek@caf.mit.edu
!{harvard,rutgers}!mit-eddie!mit-caf!vlcek

gwyn@smoke.BRL.MIL (Doug Gwyn ) (11/27/88)

In article <1537@mit-caf.MIT.EDU> vlcek@mit-caf.UUCP (Jim Vlcek) writes:
-People here paid too much attention to the pointer types, and not
-enough attention to the values!  The original cast to (char *) is only
-done to be able to correctly perform the necessary pointer arithmetic,
-for in fact ``table'' is in no sense really a pointer to char.  I'm
-suprised that the notion of *(char **) amounting to a no-op managed to
-breeze by Doug Gwyn!

Yes, I apologize.  I was concentrating on the types issue and didn't
pay attention to the fact that the struct contained a pointer to the
string to be compared not the string (char array) itself.  Sorry.
The *(char**) is indeed necessary to pick up the pointer to the string.

If you check out the wording in the articles to which I was responding,
it should be easy to see how I was misled:

>*-  Huh?  The type of the expression ((char *)table + (m * size)) is
>*-  "pointer to char", no?  And the usage on line 86 requires "pointer to
>*-  pointer to char".  If I dereference the subexpression above, e.g.
>*-  *((char *)table + (m * size)), the result type is "char", not "pointer
>*-  to char" as required by strcmp().  Or am I just being dense?

The referenced discussion is all about types and not about semantics.
It is true, as I said, that starting from a (char *) one doesn't need
to apply *(char**) to it to produce a (char *), but one DOES need to
do that to access the pointer member of the array in order to find the
string in question.  If the operation had been on the struct member
itself then the original (char *) would already have been suitable
for accessing it via a function taking (char *) pointers.