Is this ok??

Andrew Koenig ark at alice.att.com
Sun Mar 10 14:56:11 AEST 1991


John E. Davis asked a question about pointers in C.
Art Neilson reponded with a rather nasty criticism of
the question.

The trouble with this sort of criticism is that it
can be embarrassing if the criticism is mistaken.
Let's take a look at the original program and the
criticism with an eye towards sorting it all out.

In what follows, >> precedes comments by Davis
(article <DAVIS.91Mar6213546 at pacific.mps.ohio-state.edu>)
and > precedes comments by Neilson
(article <1991Mar08.191107.23161 at pilikia.pegasus.com>).

>> #include <stdio.h>

>> void fm2(s)
>> char **s;
>       ^ here we go yet again, this parameter doesn't match
>         what you're trying to pass in from fm1().
>> {
>>     *s = "Hello\n";
>      ^ you can't do this.  s points nowhere.
>        besides, you need to do strcpy(s, "Hello"),
>        the way you are initializing *s is wrong.
> 
>> }

Is it actually true that s points nowhere?  It's hard to say
without looking at the caller of fm2; we'll come to that presently.
If we assume that s points somewhere, though, there is nothing
wrong with saying

	*s = "Hello\n";

A string literal is essentially the "name" of an otherwise unnamed
initialized character array.  Thus the assignment above would make
the pointer addressed by s point to the initial character of this array.

That brings us back to the previous question: where does s point?
Let's look at fm2's caller:

>> void fm1(s)
>> char **s;
>       ^ this formal parameter to fm1 doesn't match what
>         you're passing it from main.
> 
>> {
>>     char *ss;
>>     fm2(&ss);
>          ^ here we go again.  the & is not necessary.
> 
>>     *s = ss;
>> }

Aha! fm2 is passed the address of the local variable "ss" in
function fm1.  That variable is of type "char *" so its address
is of type "char **", which matches the type of the formal
parameter of fm2.  Apparently that criticism is incorrect.

We are now in a position to understand the assignment to *s
in fm2; since s is the address of the variable ss in fm1,
*s is that variable itself.  Thus after executing this assignment,
variable ss in fm1 will point to the initial character of "Hello\n".

I see nothing wrong with that so far.  Indeed, the second criticism
in fm1 is also seen to be incorrect; the & is indeed necessary
(else the call would not be type-safe) and the call

	fm2(&ss);

has the same effect as

	ss = "Hello\n";

Now let's look at the first criticism in fm1, namely that the
formal parameter to fm1 doesn't match what's passed from main.
To check this, we need to look at main:

>> int main()
>>   {
>>       char *s;
>> 
>>       fm1(&s);
>            ^why are you passing "address of" s ?
>             s is already an address, remove the &.
> 
>>       (void) fputs(s,stdout);
>>       return(0);
>>   }

Variable s in main is of type "char *" so its address is of type
"char **".  That is the same type as the formal parameter to fm1,
so the criticism of fm1 is incorrect.  The criticism of "main"
answers its own question: if fm1 were passed s rather than &s,
the call would indeed be incorrect.

What happens inside fm1?  If we replace the call to fm2 by the
assignment having the same effect, we get this:

	char *ss;
	ss = "Hello\n";		/* the effect of the call to fm2 */
	*s = ss;

What is *s?  It's exactly the variable "s" in main.  Thus,
the effect of main should be as if its body were written:

	char *s;

	s = "Hello\n";		/* the effect of the call to fm1 */
	(void) fputs(s,stdout);
	return(0);

I don't see anything wrong with any of this, so I suspect a compiler bug.
-- 
				--Andrew Koenig
				  ark at europa.att.com



More information about the Comp.lang.c mailing list