[net.lang.c] Address of array

jst@abic.UUCP (Shack Toms) (03/05/86)

I have noticed that different compilers treat the & operator differently
when it is applied to arrays.  In particular, the UNIX compiler I have
been using warns against it.  K&R explicitly deny its legality.
However, the operation seems to me to be perfectly
reasonable when the desired result is a pointer to the array rather
than a pointer to the first element of the array.  For example,

typedef int foo[5];
foo x, y[3], *z;

if sizeof(int) == 4 then --
    sizeof *z == 20
    sizeof &**z == 4 if pointers are 4 bytes
    sizeof x == 20
    sizeof y[2] == 20
    sizeof **z == 4
    sizeof *x == 4
    sizeof *y[2] == 4
    z = &x is illegal although the types would match
    z = x is quasi-legal, the types mismatch, lint should complain
    z = &y[2] is illegal, for no good reason (my opinion)
    z = y + 2 is legal
    (int *) z == *z /* The pointer to array == pointer to first element */
    (int *) (z + 1) != *z + 1  /* But their types differ (with implications) */
    (int *) (y + 2) == y[2]
    y[2]+1 is a pointer to y[2][1]
    &y[2]+1 should be a pointer to y[3], but is illegal

The algorithms in question use z as a pointer to an array (usually)
within arrays.  It is useful sometimes to have z point to an isolated
array however.  The pointer increment operation (z++) is useful, so
it is desireable to not interchange the meanings of (pointer to array)
and (pointer to first element of array).

Where allowed in the language, an array name as an lvalue refers to
the entire array (e.g. sizeof) wheras an array name as an rvalue
evaluates to a constant pointer to the first element of the array.

Trying to use this to solve the problem, I create 'foo' as a struct
which contains the array as its sole field.  Then, when I want to access
the array as an lvalue, I use the struct name.  When I want to access
the array as an rvalue, I use the field name.

This ends up looking like:

typedef struct { int r[5]; } foo;
foo x, y[3], *z;

if sizeof(int) == 4 then --
    sizeof *z == 20
    sizeof &*(*z.r) == 4 if pointers are 4 bytes
    sizeof x == 20
    sizeof y[2] = 20
    sizeof *(*z.r) == 4
    sizeof *(x.r) == 4
    sizeof *(y[2].r) == 4
    z = &x now legal and produces the desired result
    z = x.r is just as quasi-legal as before
    z = &y[2] now legal and produces the desired result
    z = y + 2 is still legal
    (int *) z == *z.r /* The pointer to array == pointer to first element */
    (int *) (z + 1) != *z.r + 1/* But their types differ (with implications) */
    (int *) (y + 2) == y[2].r
    y[2].r+1 is a pointer to y[2].r[1]
    &y[2]+1 is a pointer to y[3], now is legal

This now does everything I would like with (y[2] = x) now being legal
as a bonus (on compilers which allow structure assignments.)  The problem
is that it is clumsy to have to keep writing .r whenever the array is
used as an rvalue.

Since the generalization of array references so that lvalues are
defined (and refer to the entire array) is useful, and is compatible
with the rest of the language definition, and is allowed in many
existing compilers... Why not make it official?

I am aware that this does not help with array assignments (as
'struct foo' does.)

Any comments?

Shack Toms @ Allen-Bradley

-- Is it warm in here, or is it just me?

greg@utcsri.UUCP (Gregory Smith) (03/08/86)

In article <750@abic.UUCP> jst@abic.UUCP (Shack Toms) writes:
>I have noticed that different compilers treat the & operator differently
>when it is applied to arrays.  In particular, the UNIX compiler I have
>been using warns against it.  K&R explicitly deny its legality.
>However, the operation seems to me to be perfectly
>reasonable when the desired result is a pointer to the array rather
>than a pointer to the first element of the array.  For example,
>[examples]

The problem is that & can only be used on lvalues, and an array can
never be an lvalue, even though its address is known. This is done
because of the automatic 'array-to-pointer' conversion in C. If an
array was an lvalue, what could you assign to it? another array! but
this second array reference would be automatically converted to a
pointer so that wouldn't work.

I agree that it is really a design flaw in the language, to make
it illegal to form a pointer to an array. & should work on any
'object' ( an object of known type residing in memory at a computable
address ) where an object is an lvalue or an array.

The problem could also be solved by allowing arrays to be lvalues.
The array-to-pointer conversion would have to be suppressed depending
on the operation being done on the array. If the array was the object of a
&, or if it was on one side of an '=', with an identical type array on
the other side, the array-to-pointer conversion would not be done. This
would allow array assignments within the current syntax of c. It would not
allow arrays to be passed as parameters, though, since parameter types of
called functions are not known to the compiler. The semantics as described
above for the '=' operator would probably very messy to implement, too.
For these reasons I think that & should be allowed but not =.

Incidentally, the language as described in K&R requires the array-to-pointer
type conversion to be supressed depending on the context of the array, but
only in one case, the object of a sizeof:

	char line[80];
	sizeof( line )	== 80	/* line not converted to (char*) */
	sizeof( line+1 ) == 4	/* or 2 or whatever sizeof(char*) is */

This exception is noted in K&R 7.2 : "When [ sizeof is ] applied to an array,
the size is the total number of bytes in the array". I.e. they are noting that
it is a special case of array treatment. (7.2 of the language reference,
Appendix A ).

Adding another, similar special treatment would allow pointers to arrays.
'&line' in the above example would be of type ( char (*)[80]).

-- 
"So this is it. We're going to die."	- Arthur Dent
----------------------------------------------------------------------
Greg Smith     University of Toronto       ..!decvax!utzoo!utcsri!greg

throopw@dg_rtp.UUCP (Wayne Throop) (03/09/86)

> I have noticed that different compilers treat the & operator differently
> when it is applied to arrays.  In particular, the UNIX compiler I have
> been using warns against it.  K&R explicitly deny its legality.
> However, the operation seems to me to be perfectly
> reasonable when the desired result is a pointer to the array rather
> than a pointer to the first element of the array.

I agree that C's treatment of array/function/struct addresses is
inconsistant, confusing, and limiting.  In essence a small notational
convenience was traded for a large consistancy headache.  I think the
tradeoff was wrong, but I'm not sure that your proposal would clarify
things.  I'd hesitate to evaluate textually and syntactically identical
constructs differently based on whether an lvalue or an rvalue is needed
in the current context.  This would pile more confusion on an already
dismal situation.
-- 
Wayne Throop at Data General, RTP, NC
<the-known-world>!mcnc!rti-sel!dg_rtp!throopw

kwh@bentley.UUCP (KW Heuer) (03/11/86)

In article <211@dg_rtp.UUCP> dg_rtp!throopw (Wayne Throop) writes:
>I agree that C's treatment of array/function/struct addresses is
>inconsistant, confusing, and limiting.  In essence a small notational
>convenience was traded for a large consistancy headache.  I think the
>tradeoff was wrong ...

Yeah, arrays are really second-class citizens in C.  I think it would have
been possible to make the array a "real" datatype, with [] an array (rather
than pointer) operator; I'd be quite willing to write &a[0] in lieu of the
automatic array-to-pointer conversion.  Of course it's too late to change
things in C; too many programs depend on it.  And C++ is committed to C
compatibility.  Are there any plans for a "D" language?

I already posted my comments on function addresses, so I won't discuss them
here.  Why do you include struct addresses in your complaint?  I don't see
anything inconsistent, confusing, or limited in them, at least nothing
analagous to function and array addresses.

Karl W. Z. Heuer (ihnp4!bentley!kwh), The Walking Lint.

rbj@icst-cmr (Root Boy Jim) (03/12/86)

	From: Wayne Throop <dg_rtp!throopw>
	Subject: Re: Address of array
	Date: 9 Mar 86 05:02:13 GMT
	To: info-c@brl-smoke.arpa
	
	> I have noticed that different compilers treat the & operator differently
	> when it is applied to arrays.  In particular, the UNIX compiler I have
	> been using warns against it.  K&R explicitly deny its legality.
	> However, the operation seems to me to be perfectly
	> reasonable when the desired result is a pointer to the array rather
	> than a pointer to the first element of the array.
	
	I agree that C's treatment of array/function/struct addresses is
	inconsistant, confusing, and limiting.  

I diagree violently (so what else is new?). The resolution of pointers
and arrays is one of the *strengths* of C. Admittedly there are a few
glitches, such as when the sizeof operator is applied to an array. Ironically,
this glitch was added to *help* the user. Personally, when a formal
parameter is declared as a local array, I would like to see sizeof
return the same as if it was a global.

	In essence a small notational
	convenience was traded for a large consistancy headache.  I think the
	tradeoff was wrong, but I'm not sure that your proposal would clarify
	things.  I'd hesitate to evaluate textually and syntactically identical
	constructs differently based on whether an lvalue or an rvalue is needed
	in the current context.  This would pile more confusion on an already
	dismal situation.
	
All the compilers I've seen give a warning, but generate &array[0].

davidsen@steinmetz.UUCP (Davidsen) (03/14/86)

In article <211@dg_rtp.UUCP> throopw@dg_rtp.UUCP (Wayne Throop) writes:
>> I have noticed that different compilers treat the & operator differently
>> when it is applied to arrays.  In particular, the UNIX compiler I have
>> been using warns against it.  K&R explicitly deny its legality.
>> However, the operation seems to me to be perfectly
>> reasonable when the desired result is a pointer to the array rather
>> than a pointer to the first element of the array.
>
>I agree that C's treatment of array/function/struct addresses is
>inconsistant, confusing, and limiting.  In essence a small notational
>convenience was traded for a large consistancy headache.  I think the
>tradeoff was wrong, but I'm not sure that your proposal would clarify
>things.

I believe that to support reasonable portable code C *must* allow the address
operator on an array, even if it is not required. Consider:

prog.c:
	#include "globals.h"  /* project global symbols and types */

	foo() {
	  LOCAL m,n;

	  process(&m);
	}

globals.h:
	typedef long LOCAL[10];

================
Since LOCAL is a typedef which is an array, the programmer would not be
able to write code which would work with a legal typedef for LOCAL
unless the & operator was allowed for an array. To require special code
to handle arrays and scalars defeats the intent of information hiding,
and requires global changes to the source is a typedef is changes, for
instance, from an array to a structure.

This was pointed out to me by someone on X3J11, but I can't remember
who in order to give credit for this example.
-- 
	-bill davidsen

	seismo!rochester!steinmetz!--\
       /                               \
ihnp4!              unirot ------------->---> crdos1!davidsen
       \                               /
        chinet! ---------------------/        (davidsen@ge-crd.ARPA)

"It seemed like a good idea at the time..."

throopw@dg_rtp.UUCP (Wayne Throop) (03/17/86)

>>I agree that C's treatment of array/function/struct addresses is
>>inconsistant, confusing, and limiting.  [...]

> [...] Why do you include struct addresses in your complaint?  I don't see
> anything inconsistent, confusing, or limited in them, at least nothing
> analagous to function and array addresses.

Ah.  Perhaps that *was* confusing of me.  I didn't mean to imply that
handling of arrays, functions and structures are all incorrect.  Just
that the treatment of each of these is not like the treatment of either
of the others.  In some sense, there isn't a "right" way to do it...
it's just that C doesn't treat similar cases (aggregates like arrays and
structs, for example) in analogous ways, and this is inconsistant.

> Karl W. Z. Heuer (ihnp4!bentley!kwh), The Walking Lint.
-- 
Wayne Throop at Data General, RTP, NC
<the-known-world>!mcnc!rti-sel!dg_rtp!throopw

jsdy@hadron.UUCP (Joseph S. D. Yao) (03/18/86)

In article <2293@utcsri.UUCP> greg@utcsri.UUCP (Gregory Smith) writes:
>In article <750@abic.UUCP> jst@abic.UUCP (Shack Toms) writes:
>>I have noticed that different compilers treat the & operator differently
>>when it is applied to arrays.  In particular, the UNIX compiler I have
>>been using warns against it.  K&R explicitly deny its legality.
>>However, the operation seems to me to be perfectly
>>reasonable when the desired result is a pointer to the array rather
>>than a pointer to the first element of the array.  ...
>I agree that it is really a design flaw in the language, to make
>it illegal to form a pointer to an array. & should work on any
>'object' ( an object of known type residing in memory at a computable
>address ) where an object is an lvalue or an array.
>...

I don't think it's reasonable to call this a flaw.  In fact, most
C compilers of which I am aware will tacitly (or sometimes with
noisy complaint) accept &array_name to be identical to array_name.
The problem is, an array name is often used as a _constant_ of type
pointer-to-______.  You cannot take the address of other constants
(e.g. &1).  It might be nice to generate an object containing the
constant, and take the address of that; but that's for more complex
and unmanageable languages than C.

[Gentle reader:  before flaming me down to slime, please stop and
think how this -- admittedly slightly off-beat -- model of an array
name fits the usage, and how it might be a nice alternative view to
your own.]

The history, of course, is that in early C only atomic objects could
be manipulated in single operations, like assignament or function
arguments or returns.  An array is not an atomic object.  A pointer
is.  Therefore, when you needed to use an array name as an atomic
object, you had to coerce it to a constant of type ptr-to-___.  A
few obvious inconsistencies show up that are a result of this:
	int x[5];
	sizeof(x) == 5*sizeof(int), because we are referring to
	the array as a whole;
	sizeof(x + 1) == sizeof(int *), because to add we have to
	coerce it to pointer, etc.
and, of course, when passed as an argument only the address strains
through.

I don't really see what the problem is that people are moaning
about.  If you want a pointer to the array, the array name itself
coerces to a pointer containing the memory location at the beginning
of the array.  There is no such thing as a pointer to the whole
array:  that is a Pasqualische or Fortranian notion.  Pointers, in
C, only point to atomic or aggregate (structure/union) objects.  I
whole-heartedly agree that for some uses it is rather nice to use
such things.  That is why (excuse me while I put on my flak jacket
and asbestos suit) C is not the only language in the world worth
using.

(Just, almost.)
-- 

	Joe Yao		hadron!jsdy@seismo.{CSS.GOV,ARPA,UUCP}

throopw@dg_rtp.UUCP (Wayne Throop) (03/18/86)

> 	[...] C's treatment of array/function/struct addresses is
> 	inconsistant, confusing, and limiting.  
>
> I diagree violently (so what else is new?). The resolution of pointers
> and arrays is one of the *strengths* of C.

Actually, you disagree needlessly :-).  I said that things were treated
inconsistantly, not that array/pointer equivalence is a not-good idea.

> Admittedly there are a few glitches,

Ah, you've noticed that too, eh?

> such as when the sizeof operator is applied to an array. Ironically,
> this glitch was added to *help* the user.

Glitches added to help the user are still glitches.  And, in the end, I
question whether they actually help the user.

> Personally, when a formal
> parameter is declared as a local array, I would like to see sizeof
> return the same as if it was a global.

You too?  Good.  You listening, ANSI?

> 	In essence a small notational
> 	convenience was traded for a large consistancy headache.  I think the
> 	tradeoff was wrong, [...]
>
> All the compilers I've seen give a warning, but generate &array[0].

Let me clarify what small notational convenience and what consistancy
headache I am talking about here.  The notational convenience is that an
array name "means" the address of the first element of the array.  The
consistency headache is that then addressing (and "mentioning") of
arrays and other things (such as structs) does not behave similarly, and
it becomes impossible to (legally, formally) take the address of an
entire array (at least, without adding warts to the warts and making yet
another "glitch").

The idea of array/pointer equivalence would cause *much* fewer problems
if the question of notational convenience of passing arrays (by
reference) hadn't clouded the issue.  This led directly to the common
confusions about whether definitions of pointers reserve
space for the items pointed to (and as to whether array
declarations do, also), the confusion of whether a structure name
indicates the address of the structure or it's contents, the inability
to treat arrays by value (since you get a reference whenever the name of
the array is mentioned), and so on and on.

I am not arguing here from a "language purity" high horse.  I am saying
that actual experience with C and the type of errors that are commited
in the use of C make me think that the treatment of array and function
addressing (and the fact that these things are different from struct
addressing) has spread confusion.  Further, this confusion has made the
C language much harder to master then it "ought" to be, and has obscured
some of its strong points, such as array/pointer equivalence.

-- 
Wayne Throop at Data General, RTP, NC
<the-known-world>!mcnc!rti-sel!dg_rtp!throopw

rh@cs.paisley.ac.uk (Robert Hamilton) (03/19/86)

>In article <211@dg_rtp.UUCP> throopw@dg_rtp.UUCP (Wayne Throop) writes:
>>> I have noticed that different compilers treat the & operator differently
>>> when it is applied to arrays.  In particular, the UNIX compiler I have
>>> been using warns against it.  K&R explicitly deny its legality.
>>> However, the operation seems to me to be perfectly
>>> reasonable when the desired result is a pointer to the array rather
>>> than a pointer to the first element of the array.
>>
>>I agree that C's treatment of array/function/struct addresses is
>>inconsistant, confusing, and limiting.  In essence a small notational
>>convenience was traded for a large consistancy headache.  I think the
>>tradeoff was wrong, but I'm not sure that your proposal would clarify
>>things.
>
>I believe that to support reasonable portable code C *must* allow the address
>operator on an array, even if it is not required. Consider:
>
>prog.c:
>	#include "globals.h"  /* project global symbols and types */
>
>	foo() {
>	  LOCAL m,n;
>
>	  process(&m);
>	}
>
>globals.h:
>	typedef long LOCAL[10];
>
>================
>Since LOCAL is a typedef which is an array, the programmer would not be
>able to write code which would work with a legal typedef for LOCAL
>unless the & operator was allowed for an array. To require special code
>to handle arrays and scalars defeats the intent of information hiding,
>and requires global changes to the source is a typedef is changes, for
>instance, from an array to a structure.

Taking the address of an array just doesnt make sense in C.
You can see the reason if you know why the following bit of
code also won't work:
int a[10];
int *b;
a=b; /* makes no sense */
a+=1; /* ditto */
b=a; /* ok of course */

The decl. a[10] does 2 things:
 1. reserves storage for 10 elements
 2. lets the compiler know that "a" is an int * to
    of the first element reserved.
    It does *not* reserve storage for a pointer to the storage.
So "&a" only exists during compilation, in the sense that the
compiler holds the address of the reserved storage somewhere
that "somewhere" has an address at compile time.
The decl. int *b on the other hand does 2 different things.
1. lets the compiler know that "b" is an int * ( for pointer arithmetic)
2. and reserves a storage location for b.
   so &b does exist at run time.

What I suppose I'm trying to say is that a is a constant and b is a variable.

Maybe what is wanted is the for the compiler to be "clever"
and assume that if you ask for the address of a constant
you really want the constant ?
-- 
UUCP:	...!seismo!mcvax!ukc!paisley!rh
DARPA:	rh%cs.paisley.ac.uk		| Post: Paisley College
JANET:	rh@uk.ac.paisley.cs		|	Department of Computing,
Phone:	+44 41 887 1241 Ext. 219	|	High St. Paisley.
					|	Scotland.
					|	PA1 2BE

bet@ecsvax.UUCP (Bennett E. Todd III) (03/19/86)

I agree that the inconsistancy between array name semantics and
structure name semantics is unfortunate. The extensions of structure
assignment, parameter passing by value, and returning by value, are
distasteful. Aggregates, both arrays and structures, should not be
"automagically" copied around by the compiler; instances of their names
as rvalues without explicit dereferencing should be converted to
pointers in BOTH cases. Note that (re)establishing the notion that a
structure name evaluates to a constant pointer to that structure removes
the distinction between the "." and "->" operators for structure member
dereference, which removes a popular source of subtle portability bugs
(to and from compilers that use the old, simpler semantics). D. Gary
Grady (dgary@ecsvax.UUCP) just pointed this out to me, and added that
this frees up the operator "->", which we could use for longjmp:-)

While I'm yapping about the big steps backward that C has made, let me
add the tightening up of the semantics of "goto", making jump tables
impossible. Switch statements are ideal for some things; not for
everything. If you want to construct efficient finite state automata you
need a jump table, without the frills forced on you by the semantics of
the switch statement. Let "label" be a new reserved word, for a new data
type, not convertable to any other. Let labels in code of the form
"<name>:" be constants of type label (and have the compiler do forward
referencing correctly, either with multiple passes or with
backpatching). Let me declare constant, initialized arrays of type
label. Grrhhh. Have to write my own compiler. Grrhhh. Let's call the new
language "C--".

-Bennett
-- 

Bennett Todd -- Duke Computation Center, Durham, NC 27706-7756; (919) 684-3695
UUCP: ...{decvax,seismo,philabs,ihnp4,akgua}!mcnc!ecsvax!duccpc!bet

garry@batcomputer.TN.CORNELL.EDU (Garry Wiegand) (03/21/86)

In a recent article jsdy@hadron.UUCP (Joseph S. D. Yao) wrote:
>...  There is no such thing as a pointer to the whole
>array:  that is a Pasqualische or Fortranian notion.  Pointers, in
>C, only point to atomic or aggregate (structure/union) objects...

Are you sure of this? I sometimes write:
	
	foo (ap) register float (*ap)[4][4]; {... (*ap)[0][0] = 33; ...}

I do this because my compiler (DEC/Vms) ends up making slightly better
use of registers than if I wrote:

	foo (array) float array[4][4]; {... array[0][0] = 33; ...}

(and because it's slightly more pleasing to my brain actually to say "pointer-
to-array" if that's what I'm thinking of). Are you saying my syntax is legal
only by the grace of DEC?

garry wiegand
garry%cadif-oak@cu-arpa.cs.cornell.edu

tps@sdchem.UUCP (Tom Stockfisch) (03/21/86)

[]
>>>I have noticed that different compilers treat the & operator differently
>>>when it is applied to arrays.  In particular, the UNIX compiler I have
>>>been using warns against it.  K&R explicitly deny its legality...
>>I agree that it is really a design flaw in the language, to make
>>it illegal to form a pointer to an array. & should work on any
>>'object'...

Joe Yao replies
>...
>I don't really see what the problem is that people are moaning
>about.  If you want a pointer to the array, the array name itself
>coerces to a pointer containing the memory location at the beginning
>of the array.  There is no such thing as a pointer to the whole
>array:  that is a Pasqualische or Fortranian notion.  Pointers, in
>C, only point to atomic or aggregate (structure/union) objects.  I
>whole-heartedly agree that for some uses it is rather nice to use
>such things.  That is why (excuse me while I put on my flak jacket
>and asbestos suit) C is not the only language in the world worth
>using...

C *can* refer to whole arrays.
If you really want to take the address of an array rather than just
mentioning the array try
	struct ary {
		int	a[SIZE];
	}	arr1, arr2;
	...
	&arr1;
	f(arr1);
	arr1 =	arr2;
In this case 'arr1' by itself is not a pointer-constant but represents the
whole array (really structure) and '&arr1' refers to a pointer to the whole
array. 'arr1.a' is the more familiar pointer-constant pointing to the first
element of the array, 'f(arr1)' passes the whole array to the function
f(), and 'arr1 = arr2' assigns the whole array.

SO WHO NEEDS PASCAL?

--Tom Stockfisch, UCSD Chemistry

chris@umcp-cs.UUCP (Chris Torek) (03/21/86)

In article <58@paisley.ac.uk> rh@cs.paisley.ac.uk (Robert Hamilton)
takes exception to something in article <211@dg_rtp.UUCP> by
throopw@dg_rtp.UUCP (Wayne Throop), who writes:

>>I believe that to support reasonable portable code C *must* allow
>>the address operator on an array, even if it is not required.

Robert says:

>Taking the address of an array just doesnt make sense in C.

I think you missed the point.  Suppose you write the following:

	#include "../projlib/types.h"

	x_type	variable;

	f()
	{
		g(&variable);
		...
	}

	g(p)
		x_type *p;
	{
		x_type newvalue;

		...
		*p = newvalue;
		...
	}

This looks perfectly reasonable, and works quite well if `x_type'
is a name for a simple type, a structure, or a union.  It does not
work---indeed, it does not even compile---if `x_type' is a name
for an array.  The problem is that you are not `allowed' to know
just what `x_type' really is.

As it turns out, it is not often useful to write something like
the above if `x_type' is a name for an array, and this problem does
not seem to come up in practice---or at least I have not seen it.
And if all else fails one can always wrap the array in a structure:

	typedef struct {
		int	x_val[10];
	} x_type;

This does seem a bit of a kludge, though.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1415)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@mimsy.umd.edu

greg@utcsri.UUCP (Gregory Smith) (03/21/86)

In article <313@hadron.UUCP> jsdy@hadron.UUCP (Joseph S. D. Yao) writes:
>I don't really see what the problem is that people are moaning
>about.  If you want a pointer to the array, the array name itself
>coerces to a pointer containing the memory location at the beginning
	       ^^^^^^ ( right value wrong type. no cigar. )
>of the array.  There is no such thing as a pointer to the whole
>array:  that is a Pasqualische or Fortranian notion.  Pointers, in
>C, only point to atomic or aggregate (structure/union) objects.

Poppycock!
	char *char_ptr, (*char_ar_ptr)[80];

	++ char_ptr;	/* add 1 to the actual value of char_ptr */
	++ char_ar_ptr; /* add _80_ to the actual value of char_ar_ptr */
			/* i.e. point to the next array in a list */

IF I can have a pointer to an array, and dereference it to get an array,
and increment it to point at the next array, WHY THE $@%@ CAN'T I POINT THE
&#&*@&* THING AT AN ARRAY!!!!!!!?????????? ( nicely, I mean )

	char line[80];	/* this is what I want to point it at */

	char_ar_ptr = &line;		/* this should work ... */
	char_ar_ptr = line;		/* this works, but gets a warning */
					/* ( and rightly so ) */
	char_ar_ptr = (char(*)[80])line; /* this works (big %$@%# deal) */

Furthermore, I don't buy the argument that array names are really load-time
constants. I am mentioning this only because I have heard this argument more
than once. I  fail to see any logic underlying this; perhaps somebody treated
array names as constants in some embryonic implementation of C because it
worked for that definition of the language. No excuse. Anyway, array names
are not always constants; any array which is local to a function has an address
which is relative to the frame pointer. Also, in

	struct foo{ int foodle; char foo_line[80]; } *foo_ptr;

the ARRAY foo_ptr->foo_line doesn't have a constant address, does it?

The prosecution rests ( for now ).
-- 
"No eternal reward will forgive us now for wasting the dawn" -J. Morrison
----------------------------------------------------------------------
Greg Smith     University of Toronto       ..!decvax!utzoo!utcsri!greg

jsdy@hadron.UUCP (Joseph S. D. Yao) (03/22/86)

In article <428@batcomputer.TN.CORNELL.EDU> garry%geology@cu-arpa.cornell.edu.arpa writes:
>In a recent article jsdy@hadron.UUCP (Joseph S. D. Yao) wrote:
>>...  There is no such thing as a pointer to the whole
>>array:  that is a Pasqualische or Fortranian notion.  Pointers, in
>>C, only point to atomic or aggregate (structure/union) objects...
>
>Are you sure of this? I sometimes write:
>	foo (ap) register float (*ap)[4][4]; {... (*ap)[0][0] = 33; ...}
>I do this because my compiler (DEC/Vms) ends up making slightly better
>use of registers than if I wrote:
>	foo (array) float array[4][4]; {... array[0][0] = 33; ...}
>(and because it's slightly more pleasing to my brain actually to say "pointer-
>to-array" if that's what I'm thinking of). Are you saying my syntax is legal
>only by the grace of DEC?
>
>garry wiegand
>garry%cadif-oak@cu-arpa.cs.cornell.edu

garry @ cadif-oak or geology:

You bring up a good point, and one that I hadn't thought to mention.
You are in fact using a pointer to a matrix!  Your compiler probably
makes different code because you don't say register float array[4][4];
in the second one.  (Try it!) I don't understand why your compiler and
lint don't complain about your code, though.  These two pieces of code
are in fact not equivalent in their declarations, though they are the
same in effect, as I will explain below.  By the way, there are (lots
of!) known problems with VMS "C", in terms of what it does versus what
all other "C" compilers do.  DEC does document most of these; I am not
at all sure how thouroughly.

The good point is this.  Whenever you pass the address of an array,
of  a n y   d i m e n s i o n , as an argument to a function, it comes
out on the other side as a pointer.  As I mentioned in the last
article, this pointer can be looked at as pointing to an object of
atomic type, no matter how deeply dimensioned the original array,
because all the array is, is a set of objects next to each other in
memory.  There are no pointers or complex aggregate objects in that
memory.  This is one way (the machine's way) of looking at it.
Another way might be to consider each level of dimensioning an
aggregate:  so, an array of int [7] is seven ints in a row; and a
matrix (2-d array) of int [5][7] is an array of 5 (array of 7 ints
in a row)s in a row.  Then x[3][4] is the 3*7+4th or 25th int in
the row.  And then, x is that elusively-sought object, the address
of [i.e., a pointer to] an array of 7 ints.  BUT, at the same time
it is the address of the first int, and the address of an array of
35 ints, and the address of a 5 X 7 matrix of ints!  How do we tell
the difference?

At this point, it might be worth sitting down and drawing a picture
of the array, both in X-Y form:
	x[0][0], x[0][1], ... , x[0][6],
	x[1][0], ...		x[1][6],
	...
	x[4][0], ...		x[4][6]
and in memory-address order:
	_x:	x[0][0]
	_x+4:	x[0][1]
		...
	_x+136:	x[4][6].

Now, obviously, if I coerce x to be an int array, I can also index it
from 0 to 34.  As mentioned above, whenever one uses an array name as
an argument to a function, it gets coerced into a pointer, and must be
declared correctly on the other side.  For instance, int **x; would be
WRONG here: why? ...
...
Because, as we said before, there are no pointers here, as there
would have to be to have a pointer to a list of pointers.  Similarly,
int *x[] is WRONG:  this also declares a list of pointers, and is
equivalent to int **x.  The declarations int *x; and int x[]; are
also equivalent to each other; and, while they may be used instead
of the truth (indexed, as I said, 0 - 34), they are not the truth.

Now, int x[5][7]; is the truth.  This can, by the way, also be written
as int x[][7]; without the compiler objecting, since the compiler does
not need to know the first subscript.  After all, you can have any
number of 7-int arrays pointed to by the passed pointer.  Since, as
stated above, int *x; and int x[]; are the same, then can anyone see
why int x[][7]; and int (*x)[7]; shouldn't be the same?  I thought
not ...

In fact, they are the same.  Much to my surprise, we have found the
elusive pointer to an array!  If I declare int (*x)[7]; I should be
able to increment x and get it to point to the next row of seven ints.
Well, hush my puppies, it does exactly that!  (Cc on 4.2BSD on ISI
68000 Q-bus machine.  Cc on Xenix 2.8b on 8086 Altos 986.  Cc on
Ultrix 1.1 on VAX 11/750.  These are the closest machines I can get
to on one hop.  All agree.)  And, in fact, this falls out logically
from the language description -- it just is a little-used turn of
phrase (as it were).  So, what does x[3][4] mean in this context?
It means index x by 3, to get the third further row of 7 ints from
the one pointed to by x; then take the 4th further int in that row.
Or, the 25th int, just as before!

Now, why is garry's code wrong?  Well, just as we can have a 1-d
alias for a 2-d array, so can we have a 3-d alias.  And that is
exactly what garry has created for us.  The declaration: int
(*x)[5][7]; is the same as int x[][5][7].  The use of this, as
(*x)[3][4], is the same as x[0][3][4].  How do we translate this?
Well, x is a pointer to a number of sequential 5X7 matrices.  In
this sequence of matrices, we are selecting the 0*35+3*7+4th int,
or the 25th int.  Therefore, the effect is the same, even though
we are saying that we are using a 3-d array!  In fact, we can take
this to as many dimensions as we want.

Yes, Virginia, this is confusing.  I'm sorry.  As I explained last
time, it has a little to do with the power of the language, and a
lot to do with history.  To change it would break a whole lot of
existing C programs, which is one of the things that ANSI X3J11 is
trying not to do (except for #endif	label's, grr grr).  And so
would should tune our mental models accordingly and learn to live
with it.

By the way:  I can understand not having lint to tell one that the
declaration and call in the C program have distinctly different
declarations.  VMS has been trying to catch up with UNIX in terms
of software tools, and seems to be falling rapidly behind.  But
surely, if you passed an &'d array to a function, a compiler error
message something like:
"tst.c", line 7: warning: & before array or function: ignored
should have come out!  Doesn't it?  That should tell you something!

Disclaimer:  any misteaks in the past 130 or so lines are purely
the result of my home workstation bottling up this message and
squirting it out past midnight so that it looks and feels like
I wrote it in my sleep ...  The C did compile the way I described,
though.  No denying it.  Pointers to arrays LIVE!
-- 

	Joe Yao		hadron!jsdy@seismo.{CSS.GOV,ARPA,UUCP}

ka@hropus.UUCP (Kenneth Almquist) (03/24/86)

> I don't really see what the problem is that people are moaning
> about.  If you want a pointer to the array, the array name itself
> coerces to a pointer containing the memory location at the beginning
> of the array.  There is no such thing as a pointer to the whole
> array:  that is a Pasqualische or Fortranian notion.  Pointers, in
> C, only point to atomic or aggregate (structure/union) objects.

Actually, there is such a thing as a pointer to an array in C; otherwise
multi-dimensional arrays would not work.  For example:

	int a[5][10];

This declares "a" to be an array of arrays.  A reference to "a" is normally
converted into a pointer to the first element of "a", and the first element
of "a" happens to be an array of 10 integers.  Now let's try to do something
with a:
	int (*p)[10];

	for (p = a ; p < a + 5 ; p++) {do something;}

Some people would prefer to replace "a + 5" with "&a[5]" on stylistic
grounds, but the latter is currently illegal because the address of arrays
cannot be taken.  If we want to have "p" point to a simple array of 10
elements, things get rather awkward:

	int b[10];

	p = ((*)[10])b;

This works, but it is not as readable as "p = &b".  If we don't want to
duplicate the constant "10", the above assignment must be changed to:

	p = ((*)[sizeof b / sizeof b[0]])b;

We cannot write "p = b" because references to "b" are converted to "pointer
to int" while "p" is of type "pointer to array[10] of int".

To repeat the basic proposal:  the conversion of an array expression to
a pointer to the first element of the array is inhibited when the "sizeof"
operator is applied to an array expression; this conversion could also
be inhibited when the "&" operator is applied to an array expression.  This
would not be a major improvement to the language, but would make certain
types of code slightly cleaner.  It is a simple extension to C which should
not break any existing programs.  In fact, the original C compiler written
by Dennis Ritchie allowed "&" to be applied to arrays.
				Kenneth Almquist
				ihnp4!houxm!hropus!ka	(official name)
				ihnp4!opus!ka		(shorter path)

dan@BBN-PROPHET.ARPA (Dan Franklin) (03/24/86)

Even though people have said that the inconsistent treatment of arrays
and structures might be a problem from an information-hiding point of
view, they've always added that they've never run into it in practice.

I'm surprised.  I have run into the problem several times in connection
with "jmpbuf", the structure (but it's not a structure) that holds the
information communicated between setjmp and longjmp.  What I've wanted to
do in several programs is use setjmp/longjmp to signal exceptions, and
sometimes intercept the exception on its way up the stack to do cleanup in
some routine.  To do this, I make my own temporary copy of the jmpbuf.
Unfortunately, I have to know that jmpbuf is an array, not a structure,
so that I can write explicit calls to bcopy (or whatever) instead of a
simple assignment.

To give a concrete example, I might have a low-level memory allocator
interface that calls malloc() and does a longjmp() if NULL is returned;
this relieves me from the tedious and error-prone testing against NULL
everywhere I call malloc().  Then in main() I use setjmp() to set up a
handler for the exception, and print a message and exit.

But some caller of my allocator might want to gain control for some reason
to do cleanup before the program exits.  So I would like to write:

    caller()
    {
        jmpbuf temp;
    
        temp = memory_failure;      /* Wrong */
        if (setjmp(memory_failure))
        {
    	    do_cleanup();
    	    memory_failure = temp;  /* Wrong */
    	    longjmp(memory_failure, 1);
        }
    
        code_that_calls_memory_allocator;
    }

Doesn't work, of course.  I have to call bcopy instead, or invent my own
structure to put the jmpbuf into.  And this also means that no matter what
some UNIX implementor might want to put into the jmpbuf, it's got to look
(to the user) like an array, which is kind of unclean.

	Dan Franklin

dan@BBN-PROPHET.ARPA (Dan Franklin) (03/24/86)

Bennett E. Todd III (mcnc!ecsvax!duccpc!bet) suggests that structure
copying is a bad idea and wants structures to behave like arrays, instead
of the reverse as everone else is suggesting.

I couldn't disagree more.  Having the compiler "automagically" copy
structures around for me is perhaps the single most useful capability
recently added to C.  It vastly simplifies the problems of dealing with
data structures.

Rob Pike's paper on the organization of the Blit software (in Software
Practice and Experience) demonstrates how clean C programming can be given
structures that can be passed as arguments and returned.  If structures
were only referenced by their addresses, using them would be much more
painful (as it used to be), since every time you returned one of the damn
things you would have to worry about where the storage was coming from.
Here's an example adapted from things in Pike's paper:

    typedef struct { int x, y; } point_t;
    point_t mk_point(int, int);

    rectangle_t output;
    output = mk_rect(mk_point(x,y), mk_point(x + 5, y + 6))

That is, make a rectangle from two points specifying the corners.  Try to
imagine doing this simple operation in a world in which structures are not
copied.  The mk_point routine would either have to take a pointer to an
empty structure to be filled in as one of its arguments, either returning
that same pointer as its return value (so it could be used in cascaded
function calls) or return a pointer to an allocated structure that would
have to be freed later (so I'd have to capture it as it went flying by in
the middle of this expression), or return a pointer to a static structure
that was overwritten with each call (which would make this expression
impossible, since the same pointer would be returned in both cases).  No
matter how you slice it, it would be a lot more than two lines of code,
and not nearly as clear.

	Dan Franklin

mike@peregrine.UUCP (Mike Wexler) (03/24/86)

In article <58@paisley.ac.uk> rh@cs.paisley.ac.uk (Robert Hamilton) writes:
>
>Taking the address of an array just doesnt make sense in C.
>You can see the reason if you know why the following bit of
>code also won't work:
>int a[10];
>int *b;
>a=b; /* makes no sense */
true
>a+=1; /* ditto */
true
>b=a; /* ok of course */
>
>The decl. a[10] does 2 things:
> 1. reserves storage for 10 elements
true
> 2. lets the compiler know that "a" is an int * to
>    of the first element reserved.
>    It does *not* reserve storage for a pointer to the storage.
true
Declarations never reserve storage for a pointer to the storage.  Your argument
doesn't make sense.
It would be useful to be able to apply the ampersand operator to any object
without knowing what its "real" type is(it could be hiddenn by typedefs). 

>So "&a" only exists during compilation, in the sense that the
>compiler holds the address of the reserved storage somewhere
>that "somewhere" has an address at compile time.
>The decl. int *b on the other hand does 2 different things.
>1. lets the compiler know that "b" is an int * ( for pointer arithmetic)
true
>2. and reserves a storage location for b.
>   so &b does exist at run time.
wrong.  This seems to be your point of confusion.  "int *b" reserves space for
b that is correct. "b" is a pointer. "&b" is a pointer to that pointer.  They
are not the same.
Here is an example program an the corresponding contents of memory on a 
hypothetical computer.
func()
{
	int i;
	int *pi
	int **ppi;

	i=512;
	pi=&i;
	ppi=&pi;
	return;
}
   address     contents      use
             |-----------|
    0001     |   0512    |   int i;
             |-----------|
    0002     |   0001    |   int *pi;
             |-----------|
    0003     |   0002    |   int *ppi;
             |-----------|
Note &pi and &ppi are the *CONSTANTS* 2 and 3.  Corresponding to the addresses
of these variables.
Notice never have I said the following construct is legal.
&i=pi;
This is completely illegal.  No compiler I know of will let you do this.
>
>What I suppose I'm trying to say is that a is a constant and b is a variable.
The address of "a" is a constant.  The address of "b" is a constant.  
The contents of both "a" and "b" are variable.  It just happens that when you
put "a" in your code the c compiler interprets it a &a.  The only thing being
asked for here is that &a also be a legal syntax for specifying the address of
a.
>
>Maybe what is wanted is the for the compiler to be "clever"
>and assume that if you ask for the address of a constant
>you really want the constant ?
Compilers already do that.
All the compilers I know of are "clever" enough to handle the following code.
typedef struct foobar FOOBAR;
func()
{
	FOOBAR s;
	FOOBAR *p;

	p=&s;
	return;
}
Yet some compilers can't handle the following code.
typedef int FOOBAR[10]
func()
{
	FOOBAR s;
	FOOBAR *p;

	p=&s;	/* should be p=s; */
	return;
}
This(&s) is what is meant by taking the address of an array.  It is perfectly
reasonable construct.
-- 
Mike Wexler
(trwrb|scgvaxd)!felix!peregrine!mike 		(714)855-3923
All of the preceding opinions are solely those of the author and do not
represent the views of any other being, sentient or abstract.

peterc@ecr1.UUCP (Peter Curran) (03/25/86)

Relay-Version: version B 2.10.1 6/24/83; site ecr1.UUCP
Path: ecr1!ecrhub!hcrvax!utzoo!watmath!clyde!cbosgd!gatech!seismo!umcp-cs!chris
From: chris@umcp-cs.UUCP (Chris Torek)
Newsgroups: net.lang.c
Subject: Re: Address of array
Message-ID: <422@umcp-cs.UUCP>
Date: Fri, 21-Mar-86 07:04:26 EST
Date-Received: Tue, 25-Mar-86 04:33:12 EST
References: <750@abic.UUCP> <211@dg_rtp.UUCP> <685@steinmetz.UUCP> <58@paisley.ac.uk>
Organization: U of Maryland, Computer Science Dept., College Park, MD
Lines: 53

Chris Torek writes (in reply to Robert Hamilton's reply to Wayne Throop):
> I think you missed the point.  Suppose you write the following:
> 
> 	#include "../projlib/types.h"
> 
> 	x_type	variable;
> 
> 	f()
> 	{
> 		g(&variable);
> 		...
> 	}
> 
> 	g(p)
> 		x_type *p;
> 	{
> 		x_type newvalue;
> 
> 		...
> 		*p = newvalue;
> 		...
> 	}
> 
> This looks perfectly reasonable, and works quite well if `x_type'
> is a name for a simple type, a structure, or a union.  It does not
> work---indeed, it does not even compile---if `x_type' is a name
> for an array.  The problem is that you are not `allowed' to know
> just what `x_type' really is.
> 
> As it turns out, it is not often useful to write something like
> the above if `x_type' is a name for an array, and this problem does
> not seem to come up in practice---or at least I have not seen it.
> And if all else fails one can always wrap the array in a structure:
> 
> 	typedef struct {
> 		int	x_val[10];
> 	} x_type;

This situation does occur - in connection with longjmp/setjmp.
The functions are passed a variable of type 'jmp_buf'.  In fact,
the functions expect an address.  With most compilers, 'jmp_buf'
is an array, and naming it produces an address.  On a few compilers,
the 'jmp_buf' is a structure (which makes more sense), but you must
pass its address (i.e. using the '&' operator).  One more portability
hiccup.
-- 

Peter Curran
Emerald City Research, Ltd.
...utzoo!ecrhub!ecr1!peterc

chris@umcp-cs.UUCP (Chris Torek) (03/26/86)

In article <2377@utcsri.UUCP> greg@utcsri.UUCP (Gregory Smith) writes:

>	char *char_ptr, (*char_ar_ptr)[80];

>	++ char_ptr;	/* add 1 to the actual value of char_ptr */
>	++ char_ar_ptr; /* add _80_ to the actual value of char_ar_ptr */
>			/* i.e. point to the next array in a list */

Yes.

>	char line[80];	/* this is what I want to point it at */

>	char_ar_ptr = &line;		/* this should work ... */

Debatable.

This works, and is probably even what you `really' mean:

	#define N	2	/* e.g. */
	char lines[N][80];

	char_ar_ptr = lines;

If you only have one line, why do you need to point at a set of
lines?
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1415)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@mimsy.umd.edu

levy@ttrdc.UUCP (Daniel R. Levy) (03/26/86)

In article <150@sdchema.sdchem.UUCP>, tps@sdchem.UUCP (Tom Stockfisch) writes:
>[]
>Joe Yao replies
>>I don't really see what the problem is that people are moaning
>>about.  If you want a pointer to the array, the array name itself
>>coerces to a pointer containing the memory location at the beginning
>>of the array.  There is no such thing as a pointer to the whole
>>array:  that is a Pasqualische or Fortranian notion.

'Scuse me, can somebody educate me as to why that would be a "Fortranian"
(I withhold opinion on the Pascal allegation) notion?  I was under the
impression that most, if not all, Fortrans implement array references pretty
much the same way that C does:  by reference to the address of the first element
in the array, with offsets computed according to the subscripts and then
automatically dereferenced for use.   The only differences I could see is
in argument passing where C can pass things by value, whereas Fortran must
pass by reference.

        FORTRAN               C

      INTEGER I(1000) <--> int i[1000];
      J = I(50)       <--> int j = i[49];
      I(3) = 8        <--> i[2] = 8;
      CALL FOO(I)     <--> foo(i); /* pass address of first element */
      CALL FOO(I(3))  <--> foo(&i[2]); /* or of another? */
      ...                      ...
      SUBROUTINE FOO(K) <> foo(k)  /* and dereference on the "other side" */
      INTEGER K(1000)      int k[1000]; {
      WRITE(*,*)K(3)       printf("%d\n",k[2]);
      ...                      ...
      END                  }
-- 
 -------------------------------    Disclaimer:  The views contained herein are
|       dan levy | yvel nad      |  my own and are not at all those of my em-
|         an engihacker @        |  ployer or the administrator of any computer
| at&t computer systems division |  upon which I may hack.
|        skokie, illinois        |
 --------------------------------   Path: ..!{akgua,homxb,ihnp4,ltuxa,mvuxa,
						vax135}!ttrdc!levy

jsdy@hadron.UUCP (Joseph S. D. Yao) (03/27/86)

In article <2377@utcsri.UUCP> greg@utcsri.UUCP (Gregory Smith) writes:

a very clear exposition of where I went wrong when I said:

>>               There is no such thing as a pointer to the whole
>>array:  that is a Pasqualische or Fortranian notion.  Pointers, in
>>C, only point to atomic or aggregate (structure/union) objects.

up to the point where he slips off the track:

>                                                       Anyway, array names
>are not always constants; any array which is local to a function has an address
>which is relative to the frame pointer. Also, in
>	struct foo{ int foodle; char foo_line[80]; } *foo_ptr;
>the ARRAY foo_ptr->foo_line doesn't have a constant address, does it?

Well ... this is true, but only the sense that  a n y  address is
relative to the address space in which it lives.  Something is not
a constant if it can be changed, right?  But you cannot say:
	foo_ptr->foo_line++
or
{
	int x[XSIZ];

	x++;
}

Despite the fact that I stupidly said there ain't no array pointers
(and I should know better, I've found where I'd written otherwise!),
I still insist that, the way C treats them right now, the model for
arrays is a pointer constant.  In stack and struct, this translates
to a pointer constant  o f f s e t .
-- 

	Joe Yao		hadron!jsdy@seismo.{CSS.GOV,ARPA,UUCP}

greg@utcsri.UUCP (Gregory Smith) (03/28/86)

In article <530@umcp-cs.UUCP> chris@umcp-cs.UUCP (Chris Torek) writes:
>In article <2377@utcsri.UUCP> greg@utcsri.UUCP (Gregory Smith) writes:
>
>>	char (*char_ar_ptr)[80];
>>
...[ a pointer to array of char ]
>>
>>	char line[80];	/* this is what I want to point it at */
>
>>	char_ar_ptr = &line;		/* this should work ... */
>
>Debatable.
	( obviously! )
>
>This works, and is probably even what you `really' mean:
>
>	#define N	2	/* e.g. */
>	char lines[N][80];
>
>	char_ar_ptr = lines;
>
>If you only have one line, why do you need to point at a set of
>lines?
Good point ... I actually hadn't thought of it exactly that way.

Two answers come to mind, though:

	(1) Because it is there. :-)

	(2) Suppose the array 'lines' is actually more than two:

		char lines[10][80];

	   Suppose I want to point char_ar_ptr at lines[i]
           ( a perfectly reasonable thing to want to do ):

		This is allowed:
		   char_ar_ptr = lines + i;
				/* let's really confuse those novices! >:-) */

		This isn't:
		   char_ar_ptr = &lines[i];  /* pointer to the ith array */

So &a[b] is not equivalent to a+b here. What a shame. I like using
&a[b] in general, and ALWAYS use it when 'a' is an array as opposed to a
pointer. Too bad I can't... especially when there's no good reason for not
being able to.
-- 
"Everything under the sun is tune, but the sun is eclipsed by the moon"
						- PF
----------------------------------------------------------------------
Greg Smith     University of Toronto      UUCP: ..utzoo!utcsri!greg

jsdy@hadron.UUCP (03/31/86)

In article <807@ttrdc.UUCP> levy@ttrdc.UUCP (Daniel R. Levy) writes:
>In article <150@sdchema.sdchem.UUCP>, tps@sdchem.UUCP (Tom Stockfisch) writes:
>>[]
>>Joe Yao replies
>>>array:  that is a Pasqualische or Fortranian notion.
>
>'Scuse me, can somebody educate me as to why that would be a "Fortranian"
Dan,

I've already recanted that whole posting.  It was written after
midnight or something [;-}].  What I think I meant was that Fortran,
like Pascal, allows you to declare an object to be of a certain
size; and the functions that operate on it know what that size was.
Compare this to C, where you have to explicitly declare what the
object you're pointing to is, before knowing its size.  Then you can
declare a pointer to the first of a sequence of arrays of a given
size.

Fortran doesn't even have pointers anyway.	(*sigh*)
-- 

	Joe Yao		hadron!jsdy@seismo.{CSS.GOV,ARPA,UUCP}

aglew@ccvaxa.UUCP (03/31/86)

struct and array pass-by-value and return - a moderate view:
Structures should always be passed by reference. Usually you only need
to look at fields, and if you need scratch space then you should declare
local variables. (Modify this for structs that fit in small packages,
like struct { short x,y; }).

However, being able to return structs without having to worry about allocating
space is a great convenience. Actually, what is needed is return of pointers,
with a convenient way of automatically allocating space for the struct that
you're going to point to. This way you get convenience and the efficiency
of not having all those extra copies to and from the stack. Doesn't everybody
use a `statalloc' package for this type of thing?

Structure and array assignment, and comparison for equality, without buffer
copies is a good thing.

greg@utcsri.UUCP (Gregory Smith) (03/31/86)

This is a repost - sorry if you've seen it, but it 'bounced', so I'm
sending it again. ( How can news bounce? The stuff attached to the returned
news ( presumably explaining the reason ) was greek to me... )

In article <530@umcp-cs.UUCP> chris@umcp-cs.UUCP (Chris Torek) writes:
>In article <2377@utcsri.UUCP> greg@utcsri.UUCP (Gregory Smith) writes:
>
>>	char (*char_ar_ptr)[80];
>>
...[ a pointer to array of char ]
>>
>>	char line[80];	/* this is what I want to point it at */
>
>>	char_ar_ptr = &line;		/* this should work ... */
>
>Debatable.
	( obviously! )
>
>This works, and is probably even what you `really' mean:
>
>	#define N	2	/* e.g. */
>	char lines[N][80];
>
>	char_ar_ptr = lines;
>
>If you only have one line, why do you need to point at a set of
>lines?
Good point ... I actually hadn't thought of it exactly that way.

Two answers come to mind, though:

	(1) Because it is there. :-)

	(2) Suppose the array 'lines' is actually more than two:

		char lines[10][80];

	   Suppose I want to point char_ar_ptr at lines[i]
           ( a perfectly reasonable thing to want to do ):

		This is allowed:
		   char_ar_ptr = lines + i;
				/* let's really confuse those novices! >:-) */

		This isn't:
		   char_ar_ptr = &lines[i];  /* pointer to the ith array */

So &a[b] is not equivalent to a+b here. What a shame. I like using
&a[b] in general, and ALWAYS use it when 'a' is an array as opposed to a
pointer. Too bad I can't... especially when there's no good reason for not
being able to.
-- 
"If you aren't making any mistakes, you aren't doing anything".
----------------------------------------------------------------------
Greg Smith     University of Toronto      UUCP: ..utzoo!utcsri!greg

rh@cs.paisley.ac.uk (Robert Hamilton) (04/01/86)

In article <260@peregrine.UUCP> mike@peregrine.UUCP (Mike Wexler) writes:
>In article <58@paisley.ac.uk> rh@cs.paisley.ac.uk (Robert Hamilton) writes:
>>
>>Taking the address of an array just doesnt make sense in C.
>>You can see the reason if you know why the following bit of
>>code also won't work:
>>int a[10];
>>int *b;
>>a=b; /* makes no sense */
>true
>>a+=1; /* ditto */
>true
>>b=a; /* ok of course */
>>
>>The decl. a[10] does 2 things:
>> 1. reserves storage for 10 elements
>true
>> 2. lets the compiler know that "a" is an int * to
>>    of the first element reserved.
>>    It does *not* reserve storage for a pointer to the storage.
>true
>Declarations never reserve storage for a pointer to the storage.  Your argument
>doesn't make sense.
>It would be useful to be able to apply the ampersand operator to any object
>without knowing what its "real" type is(it could be hiddenn by typedefs). 
>
>>So "&a" only exists during compilation, in the sense that the
>>compiler holds the address of the reserved storage somewhere
>>that "somewhere" has an address at compile time.
>>The decl. int *b on the other hand does 2 different things.
>>1. lets the compiler know that "b" is an int * ( for pointer arithmetic)
>true
>>2. and reserves a storage location for b.
>>   so &b does exist at run time.
>wrong.  This seems to be your point of confusion.  "int *b" reserves space for
>b that is correct. "b" is a pointer. "&b" is a pointer to that pointer.  They
>are not the same.

NO you misunderstand me.
My argument is a valid explanation of why C rejects the address of an array
(at least in my interpretation of what EXISTS means)
If storage is reserved for b then that storage must have a runtime address
must it not ?? And so that address is &b and can be taken as rhs.
You say so yourself :
>int *pi;
>int **pi=&pi; /**/

I don't of course mean that &b is some value sitting somewhere in memory
so you cant take the &b as a lhs .(as you say)
In the same way (int a[10]) sits in memory somewhere and has an address a
so you can say int *b=a which also happens to be &a[0].
But a itself does not sit in memory (as b does) and so &a does not exist.

The pointer/array confusion comes because
C takes a to be the address of the array rather than the array itself,
which is inconsistent with the treatment of everything else.

But enough of this, I do see the problem and agree...
-- 
UUCP:	...!seismo!mcvax!ukc!paisley!rh
DARPA:	rh%cs.paisley.ac.uk		| Post: Paisley College
JANET:	rh@uk.ac.paisley.cs		|	Department of Computing,
Phone:	+44 41 887 1241 Ext. 219	|	High St. Paisley.
					|	Scotland.
					|	PA1 2BE

guy@sun.uucp (Guy Harris) (04/03/86)

> struct and array pass-by-value and return - a moderate view:
> Structures should always be passed by reference. Usually you only need
> to look at fields, and if you need scratch space then you should declare
> local variables. (Modify this for structs that fit in small packages,
> like struct { short x,y; }).

For efficiency reasons yes, they should be passed by reference in many
circumstances.  However, the language already supports call-by-value, and it
can be convenient in many other circumstances, so use or non-use of
call-by-value should be a matter of programming style, not of language
definition.

> Structure and array assignment, and comparison for equality, without buffer
> copies is a good thing.

You are aware, of course, that comparison for equality of structures,
assuming it were added to the language, could not be implemented by a
"string compare" instruction or code sequence?  Such a sequence would
compare the padding bytes between structure members; there is no guarantee
that those bytes are ever initialized, so two structures whose values are
equal may not contain identical bit patterns.
-- 
	Guy Harris
	{ihnp4, decvax, seismo, decwrl, ...}!sun!guy
	guy@sun.arpa	(yes, really)

rbj%icst-cmr@smoke.UUCP (04/05/86)

	> Structure and array assignment, and comparison for equality, without buffer
	> copies is a good thing.
	
	You are aware, of course, that comparison for equality of structures,
	assuming it were added to the language, could not be implemented by a
	"string compare" instruction or code sequence?  Such a sequence would
	compare the padding bytes between structure members; there is no
	guarantee that those bytes are ever initialized, so two structures
	whose values are equal may not contain identical bit patterns.
	-- 
		Guy Harris
		{ihnp4, decvax, seismo, decwrl, ...}!sun!guy
		guy@sun.arpa	(yes, really)
	
Fisrt, I disagree that struxure (or array) assignments are A Good Thing.
I much prefer the model of limiting primitive data types to values that
can be held in a register on an idealized machine. So much for the
`religious' part.

Secondly, struxures could be created with the padding bytes set to
all zero bits. Then, any garbage appearing in them could only be
creating by sloppy coding practices which even *I* abhor, even
considering my widely known nonportable tendencys.

	(Root Boy) Jim Cottrell		<rbj@cmr>

sbs@valid.UUCP (Steven Brian McKechnie Sargent) (04/17/86)

> In article <260@peregrine.UUCP> mike@peregrine.UUCP (Mike Wexler) writes:
> >In article <58@paisley.ac.uk> rh@cs.paisley.ac.uk (Robert Hamilton) writes:
> >>
> >>	(Much flamage about "right" way to interpret cettes choses)
> >	(Much flamage about "right" way to interpret cettes choses)
>	(Much flamage about "right" way to interpret cettes choses)

The ANSI debate on the C standard, which has devolved into a wide variety
of entertaining circuses, recently had a sidelight into the &array issue.
When I last left it, the committee was leaning toward allowing &array so that
programmers could portably declare and use thusly:

	typedef int time_t[2];
	...
	time_t t;
	printf("%s", (time(&t), ctime(&t)));

(This objection is rather neatly removed by

	typedef struct {
		int once_upon_a[2];
	} time_t;

but never mind.
)

I lean in the opposite direction (I believe that &array is an undesirable
construct) because of the following gotcha:

	char a[200][40];
	char *b[200];
	...
	strcpy(b[i], a[i]);	/* works */
	strcpy(b[i], &a[i]);	/* works */
	strcpy(&b[i], &a[i]);	/* don't work */

Of course, adherents to strong typing will say, "Thou fool.  Declare
strcpy(char *, char *) in thy headers," and they're perfectly entitled
to their opinions.


S.

sam@delftcc.UUCP (Sam Kendall) (04/18/86)

In article <227@valid.UUCP>, sbs@valid.UUCP writes:
> When I last left it, the [ANSI] committee was leaning toward allowing &array
> so that programmers could portably declare and use thusly:
> 
> 	typedef int time_t[2];
> 	...
> 	time_t t;
> 	printf("%s", (time(&t), ctime(&t)));

The point is uniformity of reference, or, more specifically, freeing the
programmer from (some) worrying about what type underlies a typedef.  In
this case, if you want to get a pointer to a variable, you shouldn't
have to worry about whether the variable is an array or not, you should
just be able to say, for variable `v', `&v'.  Total uniformity of
reference is impossible for arrays, of course, but allowing
address-of-array brings the language a bit closer.

> (This objection is rather neatly removed by
> 
> 	typedef struct {
> 		int once_upon_a[2];
> 	} time_t;
> 
> but never mind.
> )

This won't work for jmp_buf, which must be an array in order to allow
calls with the documented syntax, for jmp_buf jb, `setjmp(jb)'.

> I lean in the opposite direction (I believe that &array is an undesirable
> construct) because of the following gotcha:
> 
> 	char a[200][40];
> 	char *b[200];
> 	...
> 	strcpy(b[i], a[i]);	/* works */
> 	strcpy(b[i], &a[i]);	/* works */
> 	strcpy(&b[i], &a[i]);	/* don't work */
> 
> Of course, adherents to strong typing will say, "Thou fool.  Declare
> strcpy(char *, char *) in thy headers," and they're perfectly entitled
> to their opinions.

No, they'll say, "Use lint, and you will find that only the first strcpy
is correct."  Lint complains about the last two.  Your gotcha is only a
gotcha if you don't use lint, in which case there are millions of other
gotchas.

----
Sam Kendall			{ ihnp4 | seismo!cmcl2 }!delftcc!sam
Delft Consulting Corp.		ARPA: delftcc!sam@NYU.ARPA

gwyn@BRL.ARPA (04/21/86)

typedef struct { whatever-you-need } jmp_buf[1];

solves the problem of the way setjmp()'s parameter is used,
with completely type-correct implementation (in the
"whatever-you-need" part).  Too bad setjmp() was defined
as taking an array parameter in the first place.

greg@utcsri (04/25/86)

In article <153@brl-smoke.ARPA> gwyn@BRL.ARPA writes:
>typedef struct { whatever-you-need } jmp_buf[1];
>
>solves the problem of the way setjmp()'s parameter is used,
>with completely type-correct implementation (in the
>"whatever-you-need" part).  Too bad setjmp() was defined
>as taking an array parameter in the first place.

I've been wondering about this... Why would you need to define jmp_buf
as a structure? It seems (1) it is impossible to write setjump or
longjmp in C (2) the contents of the buffer are completely
non-portable, so any program that looks at or alters them is
non-portable (3) you can't do anything useful with them anyway, from C.
All jmp_buf is is a certain amount of space, as far as C needs to be
concerned. I think point (3) is a bit shaky - the contents just might
be useful in certain inherently non-portable code. And it would be
nice, I agree, if jmp_buf had been defined as a structure - if only to
allow easy copying of jmp_buf records. A definition might look like
`typedef struct{ char *dummy[11];} jmp_buf;'.  But are there cases where
a structure was used out of necessity?

-- 
"For every action there is an equal and opposite malfunction"
----------------------------------------------------------------------
Greg Smith     University of Toronto      UUCP: ..utzoo!utcsri!greg