[comp.lang.c] Is ``char c; strcpy

eggert@twinsun.com (08/25/89)

Suppose we have ``strcpy'' as defined in K&R 5.5, p.106:

	void strcpy(char *s, char *t) { while (*s++ = *t++) ; }
Then
	...  char c; strcpy(&c, ""); ...		(1)

is not ANSI C, because strcpy calculates (&c) + 1, violating K&R A7.6, p.205,
which says pointer arithmetic can be applied only to a ``pointer to an object
in an array''.  Shouldn't (1) be invalid even if we invoke the standard
library's strcpy(), too?  And by extension, shouldn't the following calls to
standard routines be invalid too?

	...  char c; fread(&c, 1, 1, stdin); ...	(2)
	...  char c; read(0, &c, 1); ...		(3)

Two plausible answers to this question are:

	A.  Certain arguments to standard routines must be arrays.
	Therefore, (1), (2) and (3) are invalid calls to standard routines.

	B.  The standard library must never assume that it is being passed a
	pointer to an array if a pointer to an array containing a single
	object would be valid in that position.  An implementer must not follow
	K&R's version of strcpy, but must rewrite its body, e.g. as:

			while (*s = *t)
				s++, t++;
	or even as:
			if (*s = *t) {
				/* Both *s and *t must be arrays. */
				s++, t++;
				while (*s++ = *t++)
					;
			}

	or use some other, perhaps machine-dependent, code.

(A) seems forced, since (3) at least is a common idiom.

(B) seems overly hopeful: can we really expect implementers to get this right,
	when K&R point in the wrong direction?

gwyn@smoke.BRL.MIL (Doug Gwyn) (08/25/89)

In article <30@looney.twinsun.com> eggert@twinsun.com (Paul Eggert) writes:
>	...  char c; strcpy(&c, ""); ...		(1)
>is not ANSI C, because strcpy calculates (&c) + 1, violating K&R A7.6, p.205,

It's not a problem.  The (proposed) C standard in effect guarantees that
every object can be considered as an array of one thing, and that it is
always legal to generate a pointer to the thing one past the last element
of any array, although it is not legal to dereference such a pointer.

dfp@cbnewsl.ATT.COM (david.f.prosser) (08/25/89)

In article <30@looney.twinsun.com> eggert@twinsun.com (Paul Eggert) writes:
>Suppose we have ``strcpy'' as defined in K&R 5.5, p.106:
>
>	void strcpy(char *s, char *t) { while (*s++ = *t++) ; }
>Then
>	...  char c; strcpy(&c, ""); ...		(1)
>
>is not ANSI C, because strcpy calculates (&c) + 1, violating K&R A7.6, p.205,
>which says pointer arithmetic can be applied only to a ``pointer to an object
>in an array''.

While K&R II is a good way to learn ANSI C, it cannot take the place of
the actual standard.

Section 3.3.6, page 48, lines 9-11:

	For the purposes of these operators [binary + and -], a pointer
	to a nonarray object behaves the same as a pointer to the first
	element of an array of length one with the type of the object
	as its element type.

The rest of that section notes that it is valid to point "one past" the
last element of an array.  Thus

	char c; ... (&c + 1) ...

is valid, as long as the address is not dereferenced.

Section 4.1.6, page 100, lines 5-9:

	If a function argument is described as being an array, the
	pointer actually passed to the function shall have a value such
	that all address computations and accesses to objects (that
	would be valid if the pointer did point to the first element of
	such an array) are in fact valid.

This is part of the introduction to the entire library section of the standard.

Section 4.11.2.3, page 163, lines 36-37:

	The strcpy function copies the string pointed to by s2 (including
	the terminating null character) into the array pointed to by s1.

Similar descriptions are used for other functions.

Dave Prosser	...not an official X3J11 answer...

mike@thor.acc.stolaf.edu (Mike Haertel) (08/25/89)

In article <30@looney.twinsun.com> eggert@twinsun.com (Paul Eggert) writes:
>Suppose we have ``strcpy'' as defined in K&R 5.5, p.106:
>
>	void strcpy(char *s, char *t) { while (*s++ = *t++) ; }
>Then
>	...  char c; strcpy(&c, ""); ...		(1)
>
>is not ANSI C, because strcpy calculates (&c) + 1, violating K&R A7.6, p.205,
>which says pointer arithmetic can be applied only to a ``pointer to an object
>in an array''.

In addition to the various people who have posted pointing out that
every object is in effect an array of one element and &c + 1 is
therefore sanctioned I should like to point out that just because
certain implementations of strcpy happen to compute &c + 1, doesn't
mean it's part of the language that strcpy would compute &c + 1.  All
too often people in this newsgroup are confusing details of their
implementation with the defined behavior of the language.

/* strcpy that doesn't compute &c + 1 */
char *
strcpy(char *s, const char *t)
{
	char *r = s, c;

	while (c = *t)
		*s++ = c;
	return r;
}
-- 
Mike Haertel <mike@stolaf.edu>
``There's nothing remarkable about it.  All one has to do is hit the right
  keys at the right time and the instrument plays itself.'' -- J. S. Bach

msb@sq.sq.com (Mark Brader) (08/27/89)

> While K&R II is a good way to learn ANSI C, it cannot take the place of
> the actual standard.
> Section 3.3.6, page 48, lines 9-11:
> 	For the purposes of these operators [binary + and -], a pointer
> 	to a nonarray object behaves the same as a pointer to the first
> 	element of an array of length one with the type of the object
> 	as its element type.

Actually, this is one of the few places where it shows up that K&R II
is based on the January 1988 draft of the standard.  That sentence was
added to Section 3.3.6 later than that, as an editorial change (proposed
by me, by the way).

-- 
Mark Brader			"This process can check if this value
SoftQuad Inc., Toronto		 is zero, and if it is, it does something
utzoo!sq!msb, msb@sq.com	 child-like."		-- Forbes Burkowski

This article is in the public domain.

wolfgang@ruso.UUCP (Wolfgang Deifel) (08/28/89)

mike@thor.acc.stolaf.edu (Mike Haertel) writes:

>/* strcpy that doesn't compute &c + 1 */
>char *
>strcpy(char *s, const char *t)
>{
>       char *r = s, c;

>       while (c = *t)
>               *s++ = c;
>       return r;
>}
I think your strcpy doesn't work. First you don't increment 't', 
( while (c = *t)  is a 'loop-forever' if you don't modify t ),
and second, if you increment t the null-character isn't copied.

    Wolfgang.