[comp.lang.c] C question -- pointer to array of characters

kunkee@ficc.uu.net (randy kunkee XNX MGR) (10/18/89)

Forget that you probably wouldn't want to do the following and
consider the declaration:

	char (*foo)[];

This declares "foo" to be a pointer to an array of characters.
My question is, how can you get an assignment to "foo" without
the C compiler complaining about different levels of indirection
(ie. make "foo" point to real storage) without using a typecast?

For example:

main()
{
	char (*foo)[];
	char bar[20];

	foo = bar;
}

Does not work (well, it works, but the compiler complains).
Is my C compiler broken?

To put it another way, is there a declaration of "bar" that will
make the above assignment compile silently, and which allocates
storage for characters?
-- 
Randy Kunkee
Ferranti International Controls Corporation
12808 W. Airport Blvd.  Sugar Land, TX 77478
UUCP: uunet!ficc!kunkee       ph: (713) 274-5132

chris@mimsy.umd.edu (Chris Torek) (10/18/89)

`char (*)[]' is an evil, nefarious type which will suck you into
a pit of despair.  (Fortunately, a fierce green snake bars the way.)

In article <6569@ficc.uu.net> kunkee@ficc.uu.net (randy kunkee XNX MGR) writes:
>Forget that you probably wouldn't want to do the following and
>consider the declaration:
>
>	char (*foo)[];
>
>This declares "foo" to be a pointer to an array of characters.

More precisely, it declares foo as a pointer to array of unknown size of
characters.  Foo can then point to zero or more such arrays.  The problem
is that if foo points to two such arrays, there is no possible way to
find where the second such array begins.  (The first one begins where
foo points, but only because for all x \elem possible-sizes, 0*x gives 0.)

>My question is, how can you get an assignment to "foo" without
>the C compiler complaining about different levels of indirection
>(ie. make "foo" point to real storage) without using a typecast?

First you need an array of unknown size.  Then simply take its address.
The *only* correct way to declare an array of unknown size is as
an `extern':

	extern char bar[];
	f() { char (*foo)[]; foo = &bar; }

>For example:
>
>main()
>{
>	char (*foo)[];
>	char bar[20];
>
>	foo = bar;
>}

Here `bar' has type `array 20 of char'; in an rvalue context, this
changes to type `pointer to char', so a correct version of main()
would be

	int main() { char *foo; char bar[20]; foo = bar; return (0); }

In ANSI C (when and if it ever appears), `&bar' will produce a value
with type `pointer to array 20 of char', so a second correct version
of main() would be

	main() { char (*foo)[20]; char bar[20]; foo = &bar; exit(0); }

(There is no particular significance to the change from `return 0' to
`exit 0'.)
-- 
`They were supposed to be green.'
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

kremer@cs.odu.edu (Lloyd Kremer) (10/18/89)

In article <6569@ficc.uu.net> kunkee@ficc.uu.net (randy kunkee XNX MGR) writes:

>consider the declaration:
>
>	char (*foo)[];
>
>main()
>{
>	char (*foo)[];
>	char bar[20];
>
>	foo = bar;
>}
>
>Is my C compiler broken?

No, your C is broken.  :-)

In this usage

	char (*foo)[];

is equivalent to

	char (*foo)[0];

i.e. a pointer to an array of zero characters -- a pointer to a zero-sized
object.  Zero-sized objects do not really exist in C, and trying to use
them will put you on thin ice.  Incrementing a pointer to a zero-sized object
leaves it pointing to the same place (assuming the compiler recognizes it at
all), so it is not a very useful pointer.

Another problem is that you need a fairly recent (pseudo-ANSI) compiler to
take the address of an array in the way you want.  Older compilers will
complain "warning: & operator on array or function: ignored", and give you
a pointer to the first element of the array instead of to the array as a
whole.  Since the start of the array is coincident with the start of its
first element, this behavior can be circumvented using a cast.

Try the following:

	char (*foo)[20];  /* pointer to an array of 20 characters */
	char bar[20];     /* array of 20 characters */

#ifdef __STDC__
	foo = &bar;
#else
	foo = (char (*)[20])bar;
#endif

-- 
					Lloyd Kremer
					...!uunet!xanth!kremer
					Have terminal...will hack!

rowe@cme.nist.gov (Walter Rowe) (10/18/89)

>>>> On 17 Oct 89 22:37:59 GMT, kunkee@ficc.uu.net (randy kunkee XNX MGR) said:

kunkee> main()
kunkee> {
kunkee> 	char (*foo)[];
kunkee>  	char bar[20];
kunkee>
kunkee> 	foo = bar;
kunkee> }

(1) `bar' is an array of characters

(2) `foo' is a pointer to an array of characters, meaning that it's
    supposed to hold the array's address.  So, `foo' should hold the
    address of `bar'.

(3) The value of `bar' is the address of the first character in the
    array.  The value of `&bar' is the address of the array `bar'.

The proper assignment, as you already know from other postings, is;

    foo = &bar;

Now `foo' contains the address of the array `bar'.

The compiler was right to complain about this since you weren't using
`foo' in the manner that you declared it.  Others made that point
clear, however, no one explained the reason why.  This is not a flame,
just trying to help you understand how things are interpreted.

Walter
--
This is just my opinion ...

gwyn@smoke.BRL.MIL (Doug Gwyn) (10/19/89)

In article <6569@ficc.uu.net> kunkee@ficc.uu.net (randy kunkee XNX MGR) writes:
>	char (*foo)[];
>	char bar[20];
>	foo = bar;
>Does not work (well, it works, but the compiler complains).
>Is my C compiler broken?

No.  There are (at least) three problems in this code:
    (1) bar is the same in the assignment expression as &bar[0],
	i.e. a char*, which is not compatible with foo.
    (2) foo has an incomplete type -- it would be impossible for
	the compiler to generate code to perform pointer arithmetic
	involving foo, because the size of the object to which foo
	points has not been specified.
>To put it another way, is there a declaration of "bar" that will
>make the above assignment compile silently, and which allocates
>storage for characters?
    (3) there are five ways to allocate storage in C:
	(a) string literals
	(b) static variables
	(c) auto variables
	(d) function arguments
	(e) invocation of malloc()/realloc()/calloc()
	execution of an assignment expression is not a way to
	allocate storage.