[net.lang.c] Address of array; really structure & [array] passing

peters@cubsvax.UUCP (Peter S. Shenkin) (04/04/86)

A naive question.  When a structure containing many objects, some of which 
may be arrays, is passed, doesn't everything in it have to be copied at
execution time, so that manipulations of the contents of the passed parameter
within the called function don't affect the copy in the calling function?  
Wouldn't this also have to occur if arrays could be passed by value?

If the structures/arrays are large, doesn't this incur a large overhead?
That is, it seems to be a tradeoff between programming ease and syntactical
elegance, on the one hand, versus time as well as space, on the other.

I'm not trying to make a general argument against pass-by-value for structures
[or arrays], but isn't the practice best avoided when large structures may
be expected?  I'm thinking not only of cases when the arrays contained
within a structure are known to be large, but when space for them is 
dynamically allocated;  then you might end up building larger objects than
you had anticipated when you wrote the program.

On rereading this, perhaps I'm wrong;  if I declare
	struct {  float array[MANY];  } sarray;
and call 
	result = func(sarray);
are all the elements of sarray.array passed to func(), or is just the
address of the array copied when the structure is passed?  Enlighten me!

Peter S. Shenkin	 Columbia Univ. Biology Dept., NY, NY  10027
{philabs,rna}!cubsvax!peters		cubsvax!peters@columbia.ARPA

gwyn@BRL.ARPA (VLD/VMB) (04/06/86)

Yes, when you pass a struct as a C function parameter, it must be
copied into a place private to that invocation of the function.  This
indeed can result in high overhead.  Experienced C programmers will
pass pointers to large structs rather than the structs themselves,
when possible.  (In older versions of C, one HAD to do it this way.)

When one invokes "func(object)", all (sizeof object) bytes are
copied before the body of "func" starts executing, except when
"object" is the NAME of an array (which means the same as the address
of the first element of the array) or the name of a function.  To
accomplish a "call by reference", one writes "func(&object)",
which requires that "object" be an lvalue (i.e. have an address).

The best examples of passing actual structs instead of pointers
are probably Rob Pike's Blit data structures:
	typedef struct
		{
		short	x;		/* horizontal */
		short	y;		/* vertical */
		}	Point;
	typedef struct
		{
		Point	origin;		/* upper left corner */
		Point	corner;		/* lower right corner */
		}	Rectangle;
with typical usage:
	Point	a, b;
	jsegment( a, b, F_XOR );
These are passed by value, as a matter of convenience.  For
larger data structures such as Bitmaps, pointers are passed
to functions rather than the actual data.

Another example one often sees is
	typedef struct
		{
		double	real;		/* real part */
		double	imag;		/* imaginary part */
		}	Complex;
with typical usage:
	Complex	a, b, c, CxMul();
	a = CxMul( b, c );
This is probably the largest size struct that should be routinely
passed by value.  Our local implementation of complex arithmetic
uses pointers instead, which isn't quite as convenient.

kwh@bentley.UUCP (KW Heuer) (04/06/86)

In article <456@cubsvax.UUCP> cubsvax!peters (Peter S. Shenkin) writes:
>A naive question.  When a structure ... is passed [by value], doesn't
>everything in it have to be copied at execution time ...?  Wouldn't this
>also have to occur if arrays could be passed by value?
>If the structures/arrays are large, doesn't this incur a large overhead?

Yes, though it's partially reduced if the architecture has a fast block-
move instruction.

>That is, it seems to be a tradeoff between programming ease and syntactical
>elegance, on the one hand, versus time as well as space, on the other.
>I'm not trying to make a general argument against pass-by-value for structures
>[or arrays], but isn't the practice best avoided when large structures may
>be expected?

Indeed, most call-by-value and return-by-value structures are small (complex
numbers, coordinates of a point, etc.).  Almost all structures are passed by
reference.  Presumably if arrays had been implemented "correctly", programs
would still pass them by reference ("f(&a)" or "f(&a[0])") except in special
cases.

>On rereading this, perhaps I'm wrong;  if I declare
>	 struct {  float array[MANY];  } sarray;
>and call 
>	 result = func(sarray);
>are all the elements of sarray.array passed to func(), or is just the
>address of the array copied when the structure is passed?  Enlighten me!

The entire structure is copied, including all the elements of the array.
This is the standard kludge for passing an array or a float by value (e.g.
to a routine written in another language).