[comp.lang.c] pointers to arrays

stuart@bms-at.UUCP (Stuart D. Gathman) (11/18/86)

I am still confused about several things concerning pointers to arrays.

There does seem to be such a type, even in K & R.

1) How does one get such an animal?  The only methods I can figure are

	a) a cast: ( type (*)[] ) array_of_type
	b) a function returning such a type (but the return must use a cast!)

2) The SysV semop(2) is defined as:

	int semop(int,struct sembuf **,int)

   but in the lint library as:

	int semop(int,struct sembuf (*)[],int)

   The semop(2) definition is definitely wrong.  The lint definition
   is possibly correct.  I have ended up pretending it is:

	int semop(int,struct sembuf *,int)

   Am I really supposed to write the code like this:?

	struct sembuf s[5];
	. . .
	rc = semop(sid,(struct sembuf (*)[])s,5)

3) It seems to me that any distinction between a pointer to an array
   and a pointer to its first element is purely semantic.  (And given
   the semantic difficult of obtaining a pointer to an array, why use
   them?)  There is no pointer conversion that I can imagine involved.

4) Given:

	TYPE **foo, (*bar)[];

   both **foo and **bar refer to an object of type TYPE.  Perhaps
   this is the source of the error in the SysV documentation.

* * *

When are pointers to arrays appropriate?  

Is there an easier (and more natural) way to use them in an expression?
-- 
Stuart D. Gathman	<..!seismo!{vrdxhq|dgis}!bms-at!stuart>

ballou@brahms (Kenneth R. Ballou) (11/19/86)

In article <273@bms-at.UUCP> stuart@bms-at.UUCP (Stuart D. Gathman) writes:
>I am still confused about several things concerning pointers to arrays.
>
>There does seem to be such a type, even in K & R.
>
>1) How does one get such an animal?  The only methods I can figure are
>
>	a) a cast: ( type (*)[] ) array_of_type
Also, you could have:
	int (* foo) [10];

	foo = (int (*) [10]) malloc (4 * sizeof (int [10]))

Then, * foo, * (foo + 1), * (foo + 2), and * (foo + 3) would each have type
"array of 10 ints."

>	b) a function returning such a type (but the return must use a cast!)

No, this function could now say  return foo + 2;

>3) It seems to me that any distinction between a pointer to an array
>   and a pointer to its first element is purely semantic.

Nope, it affects address arithmetic.

--------
Kenneth R. Ballou		...!ucbvax!brahms!ballou
Department of Mathematics	ballou@brahms.berkeley.edu
University of California
Berkeley, California  94720

rep@genrad.UUCP (Pete Peterson) (11/19/86)

In article <273@bms-at.UUCP> stuart@bms-at.UUCP (Stuart D. Gathman) writes:
>I am still confused about several things concerning pointers to arrays.
>There does seem to be such a type, even in K & R.
>1) How does one get such an animal?  The only methods I can figure are
>	a) a cast: ( type (*)[] ) array_of_type

		You could declare:
		char *(linesptr)[81]; /*declares linesptr to be a pointer to 81 element
			arrays of chars. */

		Or you could have:
		typedef char line[81];
		typedef line *linept;
		linept linesptr;	/* also declares linesptr to be a pointer to
								81 element arrays of chars */	

>	b) a function returning such a type (but the return must use a cast!)
>2) The SysV semop(2) is defined as:
>		--- deleted references to SysV semop ---
>3) It seems to me that any distinction between a pointer to an array
>   and a pointer to its first element is purely semantic.  (And given
>   the semantic difficult of obtaining a pointer to an array, why use
>   them?)  There is no pointer conversion that I can imagine involved.
>
		Given the declarations above, if you have:
		line page[20];  /* declare an array of 20 "lines" */
		char *lpointer;
		lpointer = linesptr = page;  /* point at first char of first line */
		
		Now if you increment linesptr, you point to the next line
		whereas if you increment lpointer, you point to the next character;
		this is more than a semantic difference.  The distinction is
		admittedly less clear when you have something like "TYPE (*pointer)[]"
		where the size of the array is unspecified so you can't do arithmetic
		on the pointers.
		It doesn't really seem that obtaining the pointer is that difficult.
>
>When are pointers to arrays appropriate?  
>
		In the example above, the difference is apparent; otherwise, it is
		perhaps conceptually clearer if you're dealing with arrays as units
		to have pointers to those units rather than their constituents.


			pete peterson

ballou@brahms (Kenneth R. Ballou) (11/20/86)

In article <1138@genrad.UUCP> rep@genrad.UUCP (Pete Peterson) writes:
>In article <273@bms-at.UUCP> stuart@bms-at.UUCP (Stuart D. Gathman) writes:
>>I am still confused about several things concerning pointers to arrays.
>>There does seem to be such a type, even in K & R.
>>1) How does one get such an animal?  The only methods I can figure are
>>	a) a cast: ( type (*)[] ) array_of_type
>
>		You could declare:
>		char *(linesptr)[81]; /*declares linesptr to be a pointer to
					81 element arrays of chars. */
No, it does not!  It declares linesptr to be an array containing 81 elements,
each of which is a pointer to char.  Perhaps you meant to write
		char (* linesptr) [81];

--------
Kenneth R. Ballou		...!ucbvax!brahms!ballou
Department of Mathematics	ballou@brahms.berkeley.edu
University of California
Berkeley, California  94720

msb@dciem.UUCP (Mark Brader) (11/20/86)

Stuart D. Gathman (stuart@bms-at.UUCP) asks:
> I am still confused about several things concerning pointers to arrays.
> ... When are pointers to arrays appropriate?  

This has been discussed here before, but I think not recently, so let
me have a crack at a new way to explain it.

Let me set up a background by taking a couple of screens to review
pointers to elementary objects, e.g. pointers to ints.

There are basically just 2 reasons that these are used.  One reason is
to access a scalar variable of that elementary type that you can't
otherwise get at:

	swapint (x, y)
	int *x, *y;
	{
		int t;
		t = *x; *x = *y; *y = t;
	}
	/* Please, no followups about other ways to write this! */

The second reason is to point to the beginning of an array, or of part of
an array, which you are going to index into.  The array name itself is
such a pointer, but you might use a pointer anyway because the array is
dynamically allocated or declared outside your scope or because you want
to point to part of the array.

For instance:

	int *a;
	a = (int *) malloc (n * sizeof (int));	/* or (n * sizeof *a) */
	for (i = 0; i < n; ++i)
		a[i] = ...

In older environments the cast of the result of malloc could be omitted,
but this is becoming non-kosher.  Another example is:

	int *a;
	int b[50];
	...
	for (a = b;  a[0] > a[1];  ++a)
		;
	/* Now a points to the beginning of the first subarray -- part of
	   the array -- whose first two elements are in descending order */

An important special case of the second reason occurs because C does not
allow arrays to be passed to functions:

	/* Invocation */		/* Definition */
	int b[20];			foo (x)
	foo (b);			int *x;

The array name b, used as an expression (as in the function argument), is
a constant pointer which is used to initialize the pointer x in the function.
x can then be indexed off, e.g. x[i].  This special case is so important that,
IN A FUNCTION HEADER ONLY, the declaration "int *x;" can also be written as
"int x[];" or even "int x[20];", to the great confusion of novices who then
think that arrays and pointers are the same thing.

Now to answer the question.

Since C does not have any operations on entire arrays, the first of
the above two uses is not applicable to pointers to arrays.  But the
second use is entirely applicable.  So the answer is: you use a pointer-
to-array type when you want to index into AN ARRAY OF ARRAYS, otherwise
called a 2-dimensional array.  The (2-d) array name itself is such a pointer,
but you might need to declare another pointer because the space is
dynamically allocated or declared outside your scope or because you
want to point to a part of the array.

Let's modify the above examples to show this.

	char (*a)[20];	/* pointer-to-arrays-of-20-chars */
	a = (char (*)[20]) malloc (n * sizeof (char [20]));
				/* or, again, (n * sizeof *a) */
	for (i = 0; i < n; ++i)
		strcpy (a[i], ...);

or the last part might also be

	for (i = 0; i < n; ++i)
		for (j = 0; j < 20; ++j)
			a[i][j] = ...

The next example might become something like this:

	char (*a)[20];
	int b[50][20];
	...
	for (a = b;  strcmp (a[0], a[1]) > 0;  ++a)
		;

or the for-header might instead be

	for (a = b;  a[0][0] > a[1][0];  ++a)

Again, the pointer might be used to pass an array to a function.
The third example becomes:

	/* Invocation */		/* Definition */
	int b[50][20];			foo (x)
	foo (b);			int (*x)[20];

and in this special case, the declaration "int (*x)[20];" could also
be written "int x[][20];" or even "int x[50][20];".

All clear now?

Going on to Stuart's specific questions:

> 1) How does one get such an animal?  The only methods I can figure are
> 	a) a cast: ( type (*)[] ) array_of_type

Correct, but the [] shouldn't be empty.  A pointer-to-array-of-unspecified-
length makes no sense.  (Some compilers may accept it, but they shouldn't.)
See one of the examples above; this construction with malloc is about the
only time this cast should be seen.

> 	b) a function returning such a type (but the return must use a cast!)

No cast needed if the declarations are correct.  In this example,
getm is a function that allocates space for a 10 by 10 matrix of
ints, and returns a pointer to the space, the type of which, of course,
is pointer-to-array-of-10-ints.

	/* Invocation */		/* Declaration */
	int (*m)[10];			int (*getm())[10]
	int (*getm())[10];		{
	...					return (int (*)[10]) malloc
	m = getm();					(100 * sizeof(int));
	for (i = 0; i <	9; i++)		}
	    for (j = 0; j < 9; j++)
		m[i][j] = 0;

The other, and commonest, way is to use the name of a 2-dimensional array
as a value.  Its type is pointer-to-array.  For instance, if getm() could
return a constant pointer, it could be written as:

					int (*getm())[10]
					{
						static int a[10][10];
						return a;
					}

Of course there are no parentheses around the *getm in the declaration;
those occur in pointers to functions.

A fourth way to get a pointer-to-array SHOULD be to precede an array name
with &, as in:

	int (*p)[10];
	int q[10];

	p = &q;

but in older compilers this does NOT WORK; the compiler, seeing &q,
thinks that you just meant q since that is already a pointer, and
compiles the statement accordingly.

If you start with a 3-dimensional array, an element of it is a pointer
to array.  For instance, in "int a[4][5][6];", a[0] has type "int (*)[6]".
The name a itself, used as a value, is also a pointer-to-array, but it is
a pointer-to-array-of-array, specifically "int (*)[5][6]".


> 2) The SysV semop(2) is defined as ...

I haven't used semop() myself, but from my reading of the man section,
both it and the lint library are wrong.  The argument is being used to
point to the beginning of an array of structs, so it should be a plain
pointer-to-struct.

> 3) It seems to me that any distinction between a pointer to an array
>    and a pointer to its first element is purely semantic.  (And given
>    the semantic difficult of obtaining a pointer to an array, why use
>    them?)  There is no pointer conversion that I can imagine involved.

Do you mean "purely syntactic"?  Certainly there is a semantic difference,
and it occurs when you increment or index off a pointer.  If m contains
a pointer to address 10000, and m is declared "char *m", then m[1] is at
address 10001; but if m is declared "char (*m)[50]", then m[1] is at
address 10050 (and has type pointer-to-char, to m[1][0] is the char at
10050, and m[1][1] is the char at 10051).

Since m[n] is equal to *(m+n) by definition whether m is an array or a
pointer, similar remarks apply to expressions like m+1 and ++m.


A final remark...  it may be easier to grasp all this if you banish from
your head the standard phraseology, which I have been using in this
article, where "char *" is called pointer-to-char, and "int (*)[10]"
is called pointer-to-array-of-10-ints.

Instead, I suggest calling them "pointer-to-chars" and "pointer-to-arrays-
of-10-ints-each".

It is true that, at any particular time, the pointer points to only one
char or one array-of-10-ints, BUT that char or array-of-10-ints could be
the beginning of an array of such objects, which justifies the phrasing
that I suggest.  In the case of pointers to arrays, as I said, pointing
to arrays of the arrays is about the only reason they are used.


Mark Brader, utzoo!dciem!msb
#define	MSB(type)	(~(((unsigned type)-1)>>1))

braner@batcomputer.tn.cornell.edu (braner) (11/20/86)

[]

Pointers to arrays come in handy for efficiency in accessing 2-d
arrays.  See K&R about "sparse arrays".  Say you have the "page"
example:

	char page[25][80];

and you want to avoid the slow calculations needed for a direct access
such as "c = page[i][j];".  Set up another array of pointers to lines:

	char *line[25];

Initialize it once to point to the lines:

	for (i=0; i<25; i++)
		line[i] = &page[i][0];

Later you do "c = line[i][j];" - which looks the same but is MUCH faster,
since no multiplication is needed to calculate &line[i][j].  (Well, it
IS necessary to multiply i by sizeof(char *), but hopefully your compiler
is smart enough to do that by a shift, since the size is a power of two -
on most machines.)

- Moshe Braner,  Cornell Univ.

braner@batcomputer.tn.cornell.edu (braner) (11/20/86)

[]

Oops: I forgot to add that another advantage of the "char *line[]"
approach is that you can do:

	char **cp;
	cp = &line[k];
	...
	cp++;	/* point to pointer to next line */

- there is no need for a multiplication in the last statement, and,
even more important, you can do all that in a function which does not
"know" the length of a "line" - it can be written to work with any
length, by passing the line[] to it instead of page[]!  You do have
to initialize line[] first, as posted.

- Moshe Braner,  Cornell University

stuart@bms-at.UUCP (Stuart D. Gathman) (11/20/86)

In article <1138@genrad.UUCP>, rep@genrad.UUCP (Pete Peterson) writes:
> In article <273@bms-at.UUCP> stuart@bms-at.UUCP (Stuart D. Gathman) writes:
> >1) How does one get such an animal?  The only methods I can figure are
> >	a) a cast: ( type (*)[] ) array_of_type
> >	b) a function returning such a type (but the return must use a cast!)

> [ example of pointer to array declaration deleted ]

	I am quite aware of how to *declare* pointers to arrays (as a
	cursory perusal of my posting will reveal).  I want to know how
	to get a pointer to an array in an expression!  The key problem
	is that arrays are always converted to pointers to their first
	elements.

> 		typedef char line[81];
> 		typedef line *linept;
> 		linept linesptr;
> 		line page[20];  /* declare an array of 20 "lines" */
> 		char *lpointer;
	main()
	{
> 		lpointer = linesptr = page;  /* point at first char of */
	}
	
	/*
	   the above does not compile or lint (I tried it on 2 machines).  
	   A quick analysis will reveal the point of my previous posting
	   (I hope). The reference to 'page' is automatically
	   converted to a pointer to its first element.  This is how
	   arrays are treated in 'C'.  This (of type linept) is assigned
	   to linesptr without error.  'linesptr' is not the correct
	   type to assign to lpointer.
	*/

> >3) It seems to me that any distinction between a pointer to an array
> >   and a pointer to its first element is purely semantic.  (And given
> >   the semantic difficult of obtaining a pointer to an array, why use
> >   them?)  There is no pointer conversion that I can imagine involved.

> [ example of pointer arithmetic deleted ]

	Given a pointer to the first element, I can increment it by the
	number of elements in the array.  Having a pointer to an array
	conveniently remembers the number of elements for me (this would
	be especially handy with dynamically sized arrays a la algol).
	But, the aggravation of having to use casts to get such a pointer
	into an expression defeats the purpose!

***************
***  A Practical Example **********
***************

/* Let's suppose we want to use: */

#include <setjmp.h>

/* We want to have a pointer to a jmp_buf for use by error handling code */

jmp_buf *envptr;	/* envptr is a pointer to an array ! */

{
  jmp_buf local_env;	/* this is an array of int's */

  envptr = &local_env;	/* oops! illegal! */
   
  /*
	The above is very confusing, especially since there is no explanation
	for the error until you find the typedef for jmp_buf in setjmp.h!
  */

  if (!setjmp(local_env)) {
    /* . . . */
  }
}

/* how are we supposed to assign a pointer to jmpbuf to envptr ? */

/* I use: */

typedef struct { jmp_buf env; } JMP_BUF;

JMP_BUF *env;	/* using global pointer lets you nest setjmps ! */

{
  JMP_BUF local_env;

  env = &local_env;
  if (!setjmp(local_env.env)) {
    /* . . . */
    if (error) longjump(env->env);
    /* . . . */
  }
  /* cleanup */
}

*************
IS THERE A BETTER WAY ?
*************

P.S.

If you're going to suggest:

	jmp_buf loc_env[1];

Don't.  I like the structure better.
-- 
Stuart D. Gathman	<..!seismo!{vrdxhq|dgis}!bms-at!stuart>

lmiller@venera.isi.edu.UUCP (11/21/86)

In article <273@bms-at.UUCP> stuart@bms-at.UUCP (Stuart D. Gathman) writes:
>I am still confused about several things concerning pointers to arrays.
>
>There does seem to be such a type, even in K & R.
>
>1) How does one get such an animal?  The only methods I can figure are
>
>	a) a cast: ( type (*)[] ) array_of_type
>	b) a function returning such a type (but the return must use a cast!)
>

Paraphrasing myself ("Programming in C", John Wiley 1986):

   The distinction between an array, and a pointer to its first element,
   is, for the most part, not useful, IF YOU'RE DEALING WITH A 1D ARRAY.
   For a 2D array, however, the distinction is important.

   An example is a 2D array of test score data, the first index selects
   the student, the second selects the indidividual test:

   int  scores[MAX_STUDENTS][MAX_TESTS];

   A routine for computing the average of a particular test (a column),
   using conventional array subscripting:

   ---------------------------------------------------------------------- 

   double test_avg(scores, max, n)
   int  scores[][MAX_TESTS], max, n;
   {
     long  sum = 0;
     int   i;

     for (i = 0; i < max; i++)
       sum += scores[i][n];

     return (double) sum / max;
   }
   ---------------------------------------------------------------------- 

   Now the same routine using a pointer.  row_ptr will point to an
   individual ROW of the matrix (and is thus a pointer to an array),
   and we'll index off of that to get to the column:

   double test_avg (scores, max, n)
   int  scores[][MAX_TESTS], max, n;
   {
     long  sum = 0,
	   i,
	   (*row_ptr)[MAX_TESTS] = scores;	/* ptr to first ROW of scores */

     for (i = 0; i < max; i++)
       sum += (*row_ptr++)[n];

     return (double) sum / max;
   }
   ---------------------------------------------------------------------- 

What's the difference?  The second version was about 25% faster on a VAX
750 using an array with 10,000 rows.  The SLOWER the machine, the GREATER
this difference will be.

Larry Miller
lmiller@venera.isi.edu

roy@phri.UUCP (11/22/86)

	Last week I was visiting with relatives.  Didn't have much to do so
I started flipping through some green-bar that was laying around.  Turned
out to be a C program.  It had the comment "in C, arrays don't have to be
rectangular".  The author of the program is an ex-physicist, ex-Fortran
hacker, nouveau-Lisp hacker who is a civilian employee of the Army working
on machine vision.  The ensuing conversation went something like:

Me: Hey, Bob, what do you mean "arrays don't have to be rectangular"?

Bob: They don't.  In C you can have a two dimensional array with each line
	a different size, using dynamic	memory allocation.

Me: Uh, you mean an array of pointers, don't you?

Bob: It's the same thing.

Me: No it's not.

Bob: That's what they taught us.

Me: Who taught you that?  Whoever taught you that should be shot!

Bob: DEC did.  We all went to a class in C programming DEC gave.
-- 
Roy Smith, {allegra,cmcl2,philabs}!phri!roy
System Administrator, Public Health Research Institute
455 First Avenue, New York, NY 10016

"you can't spell deoxyribonucleic without unix!"

throopw@dg_rtp.UUCP (Wayne Throop) (11/26/86)

>,>>> stuart@bms-at.UUCP (Stuart D. Gathman)
>> rep@genrad.UUCP (Pete Peterson) writes:

I suspect that Stuart missed Mark Brader's excelent review of pointers
to arrays, posted here a while back.  I'll expand on some of the points
Stuart raises here, but sadly I think Stuart's example can't be coded
much "better" than he in fact codes it (at least, not in pre-X3J11 C).

>>>1) How does one get such an animal?  The only methods I can figure are
>>>     a) a cast: ( type (*)[] ) array_of_type
>>>     b) a function returning such a type (but the return must use a cast!)
>> [ example of pointer to array declaration deleted ]
>         I am quite aware of how to *declare* pointers to arrays (as a
>         cursory perusal of my posting will reveal).  I want to know how
>         to get a pointer to an array in an expression!  The key problem
>         is that arrays are always converted to pointers to their first
>         elements.

Wrongo.  Arrays are *NOT* always converted into pointers to their first
elements.  One case is old and obvious: (sizeof(arrayname)).  Another
case (actually, a set of cases including this one) is newly proposed by
X3J11: (&arrayname).  Further, the fact that arrays are often converted
to pointers to their first element does not in any way make it difficult
to get a pointer to an array in an expression (in fact, this is
trivial).  Here is a code fragment that illustrates passing a pointer of
type (int (*)[N]) to a function 'f':

        { int a[M][N];     f( a ); }

>         Given a pointer to the first element, I can increment it by the
>         number of elements in the array.  Having a pointer to an array
>         conveniently remembers the number of elements for me (this would
>         be especially handy with dynamically sized arrays a la algol).
>         But, the aggravation of having to use casts to get such a pointer
>         into an expression defeats the purpose!

Maybe.  But where did you get the strange idea that you have to use a
cast to get such a pointer?  Inside the function 'f' from above, we
might have:

        f(a) int (*a)[N]; {
            int (*orig_a)[N]) = a;
            for( ; (a-orig_a)<M; ++a )
                ...
        }

which will step the pointer a along the M arrays that make up the actual
two-dimensional array.  (Note that this isn't what Stuart wanted, as we
find out below, but it does satisfy what he said above.)

> [example using jmp_buf, mostly deleted]
>   envptr = &local_env;  /* oops! illegal! */

Note that it won't be illegal if/when X3J11 is adopted.  This will then
be the "best" way of doing what you wanted to do.

> IS THERE A BETTER WAY ? [than wrapping a struct around the arrays]

Well, the struct kludge seems like a pretty good way to me, given C's
current limitations.  I doubt there is a "better" way, barring waiting
for X3J11 compliant compilers.  Of course, you still can't recursively
typedef, so casts or the struct kludge will still be needed in some
cases.  Sigh.

--
A programming language is low level when its programs require attention
to the irrelevant.
                                --- Alan J. Perlis
-- 
Wayne Throop      <the-known-world>!mcnc!rti-sel!dg_rtp!throopw

throopw@dg_rtp.UUCP (Wayne Throop) (11/26/86)

Stuart coded an example that "ought to work" under X3J11 C like so:

> #include <setjmp.h>
> jmp_buf *envptr;
> void f(){
>   jmp_buf local_env;
>   envptr = &local_env;
>   if (!setjmp(local_env)) {
>     /* . . . */
>   }
> }

Couple of points.  A longjmp to the envptr, coded like so:

                longjmp( envptr, 1 );

would be type incorrect, since envptr has type (jmp_buf *) (that is,
type (int (*)[N])), and longjmp expects type a promoted jmp_buf type
(that is, type (int *)).  The longjmp ought to be coded:

                longjmp( *envptr, 1 );

Note that Stuart wanted a "better way" to code all this under current,
pre X3J11 C.  I note that if you don't mind the sleaziness of knowing
that jmp_buf is really an array, and what element type jmp_buf has (int,
in most cases), you can code it like so:

        #include <setjmp.h>
        int *envptr;
        void f(){
          jmp_buf local_env;
          envptr = local_env;
          if (!setjmp(local_env)) {
            /* . . . */
          }
        }

And then, the longjmp becomes just

                longjmp( envptr, 1 );

I hope everybody sees why this works.

--
A program without a loop and a structured variable isn't worth writing.
                        --- Alan J. Perlis
-- 
Wayne Throop      <the-known-world>!mcnc!rti-sel!dg_rtp!throopw

thoth@beach.cis.ufl.edu (Robert Forsman) (02/16/89)

  OK, Gordon cross wants to take the address of an array, but not in
any normal way.  If E is an array (yes I know it's upper case but
that's what he used) the &E should return a pointer to an array.  My
question is "what will you use this for?"  Pointers are usually used
to modify things, and &E I believe would be used to modify the address
of the array since that's what E is (the address of the array).  YOU
CAN'T DO THAT!!!
  Arrays are solid, cast in stone, at least until you pop 'em off the
stack.  Now if you have a pointer D that happens to point to the top
of the array, SURE, &D, because you can modify D.  E is (during it's
lifetime) pretty much a constant and shouldn't be modified.  THAT's
why you can't do &E (try &4, it fails for probably the same reason.)

   THOTH out -

"There's more postings coming your way comp.lang.Cers so wait until
I'm done before you sue me."			- me.

chris@mimsy.UUCP (Chris Torek) (02/17/89)

In article <19784@uflorida.cis.ufl.EDU> thoth@beach.cis.ufl.edu
(Robert Forsman) writes:
>... Gordon Cross wants to take the address of an array....  My
>question is "what will you use this for?"

For whatever you like.  E.g.:

	f(ptr_to_array, number_of_arrays)
		int (*ptr_to_array)[30];
		int number_of_arrays;
	{
		int i;

		for (i = 0; i < number_of_arrays; i++)
			(*ptr++)[5] = 42;
	}

	foo()
	{
		int first[2][30];
		int second[30];

		f(first, 2);
		/* now first[0][5] = 42 and first[1][5] = 42 */

		f(&second, 1);
		/* now second[0][5] = 42 */

		...
	}

Without allowing `&array' you must write

		f((int (*)[30])second, 1);

which is after all rather silly.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

jim@athsys.uucp (Jim Becker) (02/17/89)

From article <19784@uflorida.cis.ufl.EDU>, by thoth@beach.cis.ufl.edu (Robert Forsman):
> 
>   OK, Gordon cross wants to take the address of an array, but not in
> any normal way.  If E is an array (yes I know it's upper case but
> that's what he used) the &E should return a pointer to an array.  My
> question is "what will you use this for?" 

	I had a problem w/ needing this functionality where I wanted
to return a pointer to an allocated array of char* pointers via a
procedure call. C did not allow me to do this. The case was one where
I wanted the caller to get the content of a text edit buffer by
passing a pointer to a *char[] type structure. I couldn't figure out
how to do this because of the inability to pass &(*char[]). This may
be doable, but I could not not get C to do it for me. I believe
Gordons' addition would let me do this.


-Jim Becker	...!sun!athsys!jim

rbutterworth@watmath.waterloo.edu (Ray Butterworth) (02/17/89)

In article <19784@uflorida.cis.ufl.EDU>, thoth@beach.cis.ufl.edu (Robert Forsman) writes:
> 
>   OK, Gordon cross wants to take the address of an array, but not in
> any normal way.  If E is an array (yes I know it's upper case but
> that's what he used) the &E should return a pointer to an array.  My
> question is "what will you use this for?"  Pointers are usually used
> to modify things, and &E I believe would be used to modify the address
> of the array since that's what E is (the address of the array).  YOU
> CAN'T DO THAT!!!

Pointers are also used for passing things to functions.
Consider:

typdef char WorkBuffer[400];

    void
func(buf, argc, argv)
    WorkBuffer *buf;
    char **argv;
{
    /* This function does its thing assuming that buf points
     * to a work buffer containing 400 bytes.
     */
}

    int
main(argc, argv)
    char **argv;
{
    WorkBuffer buf1;
    char buf2[300];

    func(&buf1, argc, argv);
    func(&buf2, argc, argv);

    return 0;
}

Now lint, if it knows what it is doing, would complain about the
second call to func() since the first argument is of the wrong type,
(char (*)[300]) vs. (char (*)[400]).
This is a good thing.

Using the more tradition use of buffers, one would pass it to
a function simply as function(buf, argc, argv), and the parameter
type in the function would be (char *).  If the function is
something like strlen(), that is correct, but if the function
is something that always expects the same length buffer, that
is a bad thing.

Legitimizing pointers to arrays of known size is one of the
good things that the pANS has done.

fso10235@uxa.cso.uiuc.edu (02/18/89)

In your example, you state that E is an "array" and
then go on to talk about &E.

E is actually an address itself; it is the address
of the first element of the array.  Putting brackets
after any number merely dereferences to that number
plus what is in the brackets.

This is in K&R, I believe.


Felix Ortony
fso10235@uxa.cso.uiuc.edu
fortony@civilgate.ce.uiuc.edu

davidsen@steinmetz.ge.com (William E. Davidsen Jr) (02/18/89)

My reading of dbANS is that the address of array has been changed, not
fixed, and is now broken in another way. Hopefully someone will
enlighten me as to what part of the standard I'm missing.

It looks to me as though given:
	int flimflam[20];
that &flimflam has type address of int. I maintain that if flimflam is
an array [20] of int, then &flimflam is "address of array [20] of int."

Consider the code fragment:
	mytype fuzzbutt, *charlie = &fuzzbutt; /* named after cats */

if I declare the typedef as:
	typedef long mytype;
everything works. If I declare it as:
	typedef struct { int xx[20]; } mytype;
it still works. But if I say:
	typedef int mytype[20];

The code fragment fails or generates a warning on most existing compilers
due to taking the address of an array. On an ANSI compliant compiler I
*believe* that there will be a warning because the address is not of the
same type as the pointer.

Arrays are barely supported in C, in that (a) taking the address doesn't
do the same thing as the address of an int or struct, (b) an array can't
be passed as an argument, and (c) a procedure can't return an array.

I couldn't see X3J11 supporting a rewrite of arrays, but I don't believe
that defining &array to return pointer to array would hurt existing
programs, they get warnings in most cases anyway.

I could be wrong about the type returned by &array, so feel free to
identify and/or interpret the standard to correct or confirm my
understanding of it.
-- 
	bill davidsen		(wedu@ge-crd.arpa)
  {uunet | philabs}!steinmetz!crdos1!davidsen
"Stupidity, like virtue, is its own reward" -me

tim@crackle.amd.com (Tim Olson) (02/18/89)

In article <13171@steinmetz.ge.com> davidsen@crdos1.UUCP (bill davidsen) writes:
| My reading of dbANS is that the address of array has been changed, not
| fixed, and is now broken in another way. Hopefully someone will
| enlighten me as to what part of the standard I'm missing.
| It looks to me as though given:
| 	int flimflam[20];
| that &flimflam has type address of int. I maintain that if flimflam is
| an array [20] of int, then &flimflam is "address of array [20] of int."

Where in the pANS do you read that &flimflam would have type "address of
int"?  All it says in 3.3.3.2 is that

	"The result of the unary & (address of) operator shall be either
	a function designator or an lvalue that designates an object
	that is not a bit-field and is not declared with the registers
	storage-class specifier...  The result of the unary & (address-of)
	operator is a pointer to the object or function designated by
	its operand.  If the operand has type "type," the result has
	type "pointer to type."

In the Rationale section, it says:

	"Some implementations have not allowed the & operator to be
	applied to an array or a function... The Committee has endorsed
	the construct since it is unambiguous, and since data
	abstraction is enhanced by allowing the important & operator to
	apply uniformly to any addressable entity."

I don't think there is any ambiguity here.

| Consider the code fragment:
| 	mytype fuzzbutt, *charlie = &fuzzbutt; /* named after cats */
| 
| if I declare the typedef as:
| 	typedef long mytype;
| everything works. If I declare it as:
| 	typedef struct { int xx[20]; } mytype;
| it still works. But if I say:
| 	typedef int mytype[20];
| 
| The code fragment fails or generates a warning on most existing compilers
| due to taking the address of an array. On an ANSI compliant compiler I
| *believe* that there will be a warning because the address is not of the
| same type as the pointer.

AMD Am29000 High C Compiler V2.1a Fri Feb 17 16:00:19 1989      t.c 
Page 1

(c) Copyright 1987-88, MetaWare Incorporated    Serial 1-AMD999999.
Levels  LINE #
|----+----1----+----2----+----3----+----4----+----5----+----6-
             1 |typedef int mytype[20];
             2 |
             3 |mytype fuzzbutt, *charlie = &fuzzbutt;  /* should be legal */
             4 |
             5 |void
             6 |f()
             7 |{
  1          8 |        int i, *ip, a[20];
  1          9 |
  1         10 |        charlie = &a;           /* legal */
  1         11 |        charlie = &i;           /* illegal */
  1         12 |        charlie = &ip;          /* illegal */
  1         13 |}
E "t.c",L11/C12:        Type "int*" is not assignment compatible withtype "mytype*".
E "t.c",L12/C12:        Type "int**" is not assignment compatible with type "mytype*".
2 user errors   No warnings   

	-- Tim Olson
	Advanced Micro Devices
	(tim@crackle.amd.com)

chris@mimsy.UUCP (Chris Torek) (02/18/89)

In article <244@tityus.UUCP> jim@athsys.uucp (Jim Becker) writes:
>... I wanted to return a pointer to an allocated array of char*
>pointers via a procedure call.

Probably not.  You probably wanted a pointer that pointed *at* (not
`to') a block of memory (`array') containing a series of `char *'
objects each pointing at a block of memory containing a series of
`char's.  The type of such a pointer is `char **'.

You might ask, `what is the difference between a pointer that points
``at'' a block of memory and one that points ``to'' an array?'  The
distinction is somewhat artificial (and I made up the words for some
netnews posting in the past).  Given a pointer to array pa:

	int a[5];
	int (*pa)[5] = &a;	/* pANS C semantics for &a */

I can get a pointer that points `at' the array instead:

	int *p = &a[0];

The latter is the more `natural' C version of the former: typically
a pointer points at the first element of a group (here 5).  The rest
of the group can be reached via pointer arithmetic: *(p+3), aka p[3],
refers to the same location as a[3].

The pointer need not point at the first element, as long as it points
somewhere into the object:

	p = &a[2];

Now p[1] refers to a[3]; p[-2] refers to a[0].  To use pa to get at
a[3] one must write (*pa)[3] (or, equivalently, pa[0][3]).

The thing that is most especially confusing, but that really makes
the difference, is that *pa, aka pa[0], refers to the entire array
`a'.  *p refers only to one element of the array.  This can be seen
in the result produced by `sizeof': (sizeof *p)==(sizeof(int)), but
(sizeof *pa)==(sizeof(int[5]))==(5 * sizeof(int)).

Pointers to entire arrays are not particularly useful unless there
are several arrays:

	int twodim[3][5];

Now we can use pa to point to (not at) any of the three array-5-of-int
elements of twodim:

	pa = &twodim[1];	/* or pa = twodim + 1, in Classic C */

and now (*pa)[3] (or pa[0][3]) is an alias for twodim[1][3].  Note
especially that since pa[0] names the *entire* array-5-of-int at
twodim[1], pa[-1] names the entire array-5-of-int at twodim[0].
\bold{Pointer arithmetic moves by whole elements, even if those
elements are aggregates.}  Thus pa[-1][2] is an alias for twodim[0][2].

This is merely a convenience, for we can do the same with p:

	p = &twodim[1][0];

Now p points to the 0'th element of the 1'th element of twodim---the
same place that pa[0][0] names.  p[3] is an alias for twodim[1][3].  To
get at twodim[0][2], take p[(-1 * 5) + 2], or p[-3].  Arrays are are
stored in row-major order with the columns concatenated without gaps;
they can be `flattened' (viewed as linear, one-dimensional) with
impunity.  (The flattening concept extends to arbitrarily deep
matrices, so that a six-dimensional array can be viewed as a string of
five-D arrays, each of which can be viewed as a string of four-D
arrays, and so forth, all the way down to a string of simple values.%)

Once you understand this, and see why C guarantees that p[-3],
pa[-1][2], and twodim[0][4] are all the same, you are well on your way
to understanding C's memory model (not `paradigm': that means
`example').  You will also see why pa can only point to objects of type
`array 5 of int', not `array 17 of int', and why the size of the array
is required.

-----
% For fun: the six-D array `char big[2][3][5][4][6][10]' occupies
  7200 bytes (assuming one byte is one char).  If the first byte is at
  byte address 0xc400, find the byte address of big[1][0][3][1][5][5].
  I hid my answer as a message-ID in the references line.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

guy@auspex.UUCP (Guy Harris) (02/18/89)

>Pointers are usually used to modify things, and &E I believe would
>be used to modify the address of the array since that's what E
>is (the address of the array).

You may believe that, but you're wrong; in the language described by the
pANS, "E" is not the address of the array, "E" is the array itself. 
(This may be an oversimplification, but I think it gets the essential
point.)  In most contexts an array-valued expression is converted to an
expression that points to the first element of the array, but "operand
of 'sizeof'" and "operand of unary &" are contexts where it isn't
converted. 

Pointers are usually used to modify things, and you can definitely
modify an array by assigning to elements of that array:

	int (*foo)[13];
	int bar[13];

	foo = &bar;
	(*foo)[7] = 666;

should work in an ANSI C program once ANSI C exists and programs can be
written in it and compiled by ANSI C-conformant compilers.

guy@auspex.UUCP (Guy Harris) (02/18/89)

>It looks to me as though given:
>	int flimflam[20];
>that &flimflam has type address of int.

Not in dpANS C; it has type "pointer to array of 20 'int's".  It has
that type in C as implemented by most PCC-based implementations.

>I maintain that if flimflam is an array [20] of int, then &flimflam
>is "address of array [20] of int."

And the dpANS (and probably the pANS, of which I don't yet have a copy)
agrees with you.

>I couldn't see X3J11 supporting a rewrite of arrays, but I don't believe
>that defining &array to return pointer to array would hurt existing
>programs, they get warnings in most cases anyway.

X3J11 probably didn't believe it either, which is why "&array" is
supposed to have the type "pointer to array...".  Basically,
"array-valued expressions" are converted to "pointer to first element of
array" in most, but not all, contexts; "operand of 'sizeof'" and
"operand of unary &" are contexts in which this conversion isn't done. 
Check your (d)pANS copy again; it's there (at least it's in the May 13,
1988 draft, and I'd be surprised as hell if it disappeared subsequently).

thoth@beach.cis.ufl.edu (Robert Forsman) (02/19/89)

in article 13339 guy@auspex.UUCP writes
>
>  Pointers are usually used to modify things, and you can definitely
>  modify an array by assigning to elements of that array:
>
>	int (*foo)[13];
>	int bar[13];
>
>	foo = &bar;
>	(*foo)[7] = 666;
>
>  should work in an ANSI C program once ANSI C exists and programs can be
>  written in it and compiled by ANSI C-conformant compilers.
>

AUUUGH!  what happens if you say (*foo) = muck (where muck is int muck[13])
Help! somebody's screwing with my stack.  OK, lets assume this is a C 
compiler of the usual flavor (meaning one I can understand) and that foo
and bar are local variables.  For illustration purposes let's declare another
pointer to int (int *intptr;)  Now the stack might look like this.

+-----+-----+-----+----------------+-----+-----+-----+
| NULL|  0  |  0  |  (9 more ints) |  0  |  0  | NULL|
+-----+-----+-----+----------------+-----+-----+-----+
 foo    ^--bar-------------------------------^   intptr

When we modify foo the compiler generates code like

MOVE_INTO_MEMORY_ADDR     BasePointer+0,   424242

When we modify an element of bar it generates

MOVE_INTO_MEMORY_ADDR     BasePointer+8,    666		/* bar[7]=666; */

When we modify some element that intptr (it could point to an array) points to

MOVE_MEMORY_INTO_REG	  REG,     BasePointer+14	/* grab intptr    */
MOVE_INTO_MEMORY	  REG+7,  666			/* intptr[7]=666; */

Note that the compiler knows where the array bar is -vs- it has to figure out
where intptr is.  You can say bar[7] and intptr[7] but the code is slightly
different.  bar is a CONSTANT (BasePointer+1), intptr is a VARIABLE! (data at
memory location BasePointer+14).  Using *(&intptr) you can modify the memory
at Basepointer+14 but trying *(&bar) would be trying to modify the constant
BasePointer+1.

  When you say bar the comiler knows EXACTLY where the elements are.
When you use intptr the code has to go into memory to get the address
of the elements.  Since this address is stored in memory you can take
its address and modify it.  You take &bar 'cause you CANNOT modify bar
AT ALL.. You can say bar[7]=4 all you want but if you say bar=intptr
I'M GOING TO SHOOT YOU! :)-
	 this is a tongue ^

  Now messing with pointers can screw with your mind (I claim immunity)
but the point (and I know I'm going to get flamed on this) is that bar is
a constant and intptr is a variable.  I KNOW bar[7] IS A VARIABLE, BUT
bar IS NOT.  Try changing it sometime.
  Any of you wizards out there who have managed to make it this far PLEASE
support me and help stomp out the pointer/array debate, otherwise I'll
gladly let you guys rot in hell and occasionally send you a letter with
SEGMENTATION VIOLATION written on it.

  One of these days I'm going to try some of this stuff and really look at the
assembler it generates to see how correct I am ( 0, 1, .643 who knows?).

/*  Sorry if there were any typos 'cause I don't know how to use emacs-yank-
news-posting or whatever and had to copy it by hand.  Frankly I think they
should invent a version of C with training wheels, no pointers, no arrays
just ints, chars and reals and say UNSUPPORTED on the other version. */

/*  Of course my opinions are my own, I haven't recieved a word of support
	yet on this issue */   Just say maybe to .signature

chris@mimsy.UUCP (Chris Torek) (02/20/89)

In article <227300001@uxa.cso.uiuc.edu> fso10235@uxa.cso.uiuc.edu writes:
>In your example, you state that E is an "array" and
>then go on to talk about &E.
>
>E is actually an address itself....  This is in K&R, I believe.

No: look again.  If E is declared as an array, then E is actually an
array.  It is true that it is *converted* to a pointer to the first
element of that array *in rvalue contexts*.  The targets of `sizeof'
and `&' are not in rvalue contexts.  The full list of special contexts,
if I remembered them all, is

	sizeof
	unary-&
	lhs of = += -= *= /= %= <<= >>= &= |= ^=
	operand of ++ --
	lhs of `.' (structure selector---actually a special case of `&')

Of these, only `sizeof' does not give lvalue context (sizeof accepts
either lvalues or rvalues, or, with parentheses, types).  Not
surprisingly, sizeof is also the only place in this list that accepts
an array designator.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

chris@mimsy.UUCP (Chris Torek) (02/20/89)

>>	int (*foo)[13];
>>	int bar[13];
>>
>>	foo = &bar;

In article <19797@uflorida.cis.ufl.EDU> thoth@beach.cis.ufl.edu
(Robert Forsman) writes:
>AUUUGH!  what happens if you say (*foo) = muck (where muck is int muck[13])

You get an error, just as if you had said

	bar = muck;

The left hand side of an assignment operator is an lvalue context, and
an array designator (such as bar or *foo) in an lvalue context is an
error.  (The other option for the language designer is to say that if
an array designator appears on the lhs of an assignment, the rhs must
be conformable, and the elements of the arrays are copied.  But C will
not do that for you.)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

rbutterworth@watmath.waterloo.edu (Ray Butterworth) (02/21/89)

In article <227300001@uxa.cso.uiuc.edu>, fso10235@uxa.cso.uiuc.edu writes:
> In your example, you state that E is an "array" and
> then go on to talk about &E.
> E is actually an address itself; it is the address
> of the first element of the array.  Putting brackets
> after any number merely dereferences to that number
> plus what is in the brackets.
> This is in K&R, I believe.

extern int E[10];

E is NOT an address.
E is NOT a pointer.
E IS an array.
E is exactly what it looks like.

In certain contexts however, where it is illegal to use an array,
the compiler will interpret E as &E[0] to save four keystrokes
for the programmer.  This may or may not have been a good idea.
There certainly has been a lot more than four keystrokes wasted
on the net by people arguing about this unnecessary confusion.

Similarly:

NULL is NOT a null pointer.
NULL is possibly NOT a pointer at all.
NULL is NOT part of the C language.
NULL IS a mistake.

NULL can be correctly defined as 0 on all valid C compilers.
The identifier is there simply as a comment to the programmer
to indicate that he is working with a pointer.

Too many programmers think that the compiler can understand this
comment.
Too many compiler maintainers think that they are helping their
confused programmers by defining incorrect values for NULL in
the hope that some of the incorrect code will compile correctly.

NULL is a definite mistake.
It looks like it means more than it really does.
It belongs with BREAK_LOOP, BREAK_SWITCH, and other such
well-intentioned but misleading macros.
It should either have never been introduced,
or it should have been defined as part of the language.
NULL is a mistake.  Don't use it.

guy@auspex.UUCP (Guy Harris) (02/21/89)

>E is actually an address itself; it is the address
>of the first element of the array.

"E" is an array.  It is, in *most* contexts, converted to a pointer to
the first element of the array.  In dpANS C (probably pANS C as well),
"operand of 'sizeof'" and 'operand of unary &' are not among those
contexts.

>This is in K&R, I believe.

In K&R Second Edition it says what the previous paragraph says; see A7.1
Pointer Generation.

K&R First Edition says:

	An identifier is a primary expression, provided it has been
	suitably declared as discussed below.  Its type is specified by
	its declaration.  If the type of the identifier is "array of
	...", however, then the value of the identifier-expression is a
	pointer to the first object in the array, and the type of the
	expression is "pointer to ..."

	...

	   The 'sizeof' operator yields the size, in bytes, of its
	operand.  ...  When applied to an array, the result is the
	total number of bytes in the array.

This had some errors:

	1) K&R First Edition C allows you to declare something of type
	   "pointer to array ...", but the stuff in the first paragraph
	   speaks only of identifiers of type "array", not of arbitrary
	   array-valued expressions.

	   The (d)pANS fixes that, by indicating that the "array to
	   pointer to first element" conversion applies to all
	   "array-valued expressions".

	2) The stuff in the second paragraph actually renders the stuff
	   in the first paragraph not 100% correct, since in:

		char foo[73];

		return sizeof foo;

	    "foo" is *not*, in fact, a pointer to the first element of
	    "foo"; if it were, "sizeof foo" would yield the size of a
	    pointer to "char", not the size of a 73-element array of
	    "char".

	    The (d)pANS fixes that by indicating that the conversion in
	    question does not apply to the operand of the 'sizeof'
	    operator.

The (d)pANS also states that the conversion in question does not apply
to the operand of the unary & operator; this is an extension that breaks
no valid code (since, previously, you weren't supposed to apply "&" to
an array, since leaving the "&" out yielded the same result), and cleans
the language up somewhat.

guy@auspex.UUCP (Guy Harris) (02/21/89)

>AUUUGH!

Yeesh.  Stop screaming, and please get either a copy of the pANS or of K&R
Second Edition, and read it, before discussing this issue any further. 
This stuff really will work reasonably, whether you believe it yet or not.

>what happens if you say (*foo) = muck (where muck is int muck[13])

The compiler, if it's at all good, says "sorry, the left-hand side isn't
a valid lvalue, try again".  No, (d)pANS C doesn't support array
assignment.

>(Long discussion which assumes that, if you can get a pointer to an
>array you *must* be able to assign to it as a whole, and thus concludes
>that "pointer to array" is an invalid concept)

No, just because you can get a pointer to an array (BTW, C has supported
the notion of "pointer to array" for quite a while, it just made it
inconvenient to construct certain values of that type until (d)pANS C
allowed you to stick & in front of an array-valued expression) doesn't
mean you can put an array on the LHS of an assignment; not all things
you can apply the & operator to are lvalues.

Again, *please* get a copy of, say, K&R Second Edition, and read it
thoroughly before commenting any further.  Unfortunately, you'll have to
read the "C Reference Manual" appendix for this stuff; there doesn't
seem to be much in the way of tutorial information on the notion of a
pointer to an array.

karl@haddock.ima.isc.com (Karl Heuer) (02/22/89)

In article <1052@auspex.UUCP> guy@auspex.UUCP (Guy Harris) writes:
>No, just because you can get a pointer to an array doesn't mean you can put
>an array on the LHS of an assignment; not all things you can apply the &
>operator to are lvalues.

Correction.  `lvalue', as the term is used in the dpANS, does not mean
`something that can appear on the LHS of an assignment'.  In fact arrays
*are* lvalues in ANSI C.

Lvalues include two flavors of things that cannot be assigned (arrays and
consts), and two flavors of things that have no address (bitfields and
registers).  A `register const' is neither addressible nor assignable, but
it's still an lvalue.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

les@chinet.chi.il.us (Leslie Mikesell) (02/23/89)

In article <1044@auspex.UUCP> guy@auspex.UUCP (Guy Harris) writes:
>>It looks to me as though given:
>>	int flimflam[20];
>>that &flimflam has type address of int.

>Not in dpANS C; it has type "pointer to array of 20 'int's".  It has
>that type in C as implemented by most PCC-based implementations.

Does this imply that pointer math and subscripting of the returned
value is scaled by the size of the array? (i.e. would &flimflam + 1
evaluate to the same address as flimflam + 20?)

Les Mikesell

scm@datlog.co.uk ( Steve Mawer ) (02/23/89)

In article <19784@uflorida.cis.ufl.EDU> thoth@beach.cis.ufl.edu () writes:
>                 If E is an array (yes I know it's upper case but
>that's what he used) the &E should return a pointer to an array.  My
>question is "what will you use this for?"  Pointers are usually used
>to modify things, and &E I believe would be used to modify the address
>of the array since that's what E is (the address of the array).  YOU
>CAN'T DO THAT!!!

&E won't (shouldn't) modify the address since, as you say, it's already
cast in stone, so to speak.  What it *should* evaluate to is a pointer
to the address of the array.  This is clearly meaningless (and hence of
limited interest :-) since only the compiler should be interested in
where it keeps the value of E.

Most compilers that I've used will either flag an error, or will issue a
warning and *assume* that you meant &E[0] (or just E) and discard the &.

-- 
Steve C. Mawer        <scm@datlog.co.uk> or < {backbone}!ukc!datlog!scm >
                       Voice:  +44 1 863 0383 (x2153)

gwyn@smoke.BRL.MIL (Doug Gwyn ) (02/23/89)

In article <7806@chinet.chi.il.us> les@chinet.chi.il.us (Leslie Mikesell) writes:
->>	int flimflam[20];
-Does this imply that pointer math and subscripting of the returned
-value is scaled by the size of the array? (i.e. would &flimflam + 1
-evaluate to the same address as flimflam + 20?)

In essence, yes.

ark@alice.UUCP (Andrew Koenig) (02/23/89)

In article <7806@chinet.chi.il.us>, les@chinet.chi.il.us (Leslie Mikesell) writes:

> Does this imply that pointer math and subscripting of the returned
> value is scaled by the size of the array? (i.e. would &flimflam + 1
> evaluate to the same address as flimflam + 20?)

Yes.
-- 
				--Andrew Koenig
				  ark@europa.att.com

swilson@thetone.Sun.COM (Scott Wilson) (02/24/89)

The spider crawling across my ceiling asks, "Just how does Doug Gwyn
pronounce the space at the end of his name?"

        Article 17420 in comp.lang.c:
        From: gwyn@smoke.BRL.MIL (Doug Gwyn )
                                           ^


--
Scott Wilson		arpa: swilson@sun.com
Sun Microsystems	uucp: ...!sun!swilson
Mt. View, CA

friedl@vsi.COM (Stephen J. Friedl) (02/24/89)

In article <91041@sun.uucp>, swilson@thetone.Sun.COM (Scott Wilson) writes:
> The spider crawling across my ceiling asks, "Just how does Doug Gwyn
> pronounce the space at the end of his name?"
> 
>         Article 17420 in comp.lang.c:
>         From: gwyn@smoke.BRL.MIL (Doug Gwyn )
>                                            ^---

He tried to tell me once, but I couldn't hear him :-)

-- 
Stephen J. Friedl / V-Systems, Inc. / Santa Ana, CA / +1 714 545 6442 
3B2-kind-of-guy   / friedl@vsi.com  / {attmail, uunet, etc}!vsi!friedl

    "vi2000: the editor of the 21st century" -- Dr. Bertrand Meyer

guy@auspex.UUCP (Guy Harris) (02/25/89)

>>>	int flimflam[20];

...

>Does this imply that pointer math and subscripting of the returned
>value is scaled by the size of the array? (i.e. would &flimflam + 1
>evaluate to the same address as flimflam + 20?)

Yes.  That's how it works now; if you have

	int (*flimflamp)[20];

then

	flimflamp + 1

would typically point "20*sizeof (int)" bytes past where "flimflamp"
points, which is also where

	(*flimflamp) + 20

points ("*flimflamp" is an array-valued expression, and, in the (d)pANS
*and*, at least, in PCC-based pre-(d)pANS C implementations and possibly
other such implementations, is converted in that context to a pointer to
the first member of that array).

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

In article <91041@sun.uucp> swilson@sun.UUCP (Scott Wilson) writes:
>"Just how does Doug Gwyn pronounce the space at the end of his name?"
>        From: gwyn@smoke.BRL.MIL (Doug Gwyn )

That's not the form in effect when I post to a newsgroup, it's:

	Reply-To: gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>)

Somebody's mail or news system is too "smart" for its own good.

What does this have to do with C?