[comp.lang.c] avoiding explicit array sizes

swine@ccicpg.UUCP (Peter Swain) (02/18/89)

In article <807@atanasoff.cs.iastate.edu> hascall@atanasoff.cs.iastate.edu (John Hascall) writes:
	[ .. week-long discussion deleted .. ]
>>double fund_consts[] = {
>>	3.14159265,
>>	2.7182818,
>>	6.02E23,
>>};
>
>   Of course, adding:
>     #define N_FCONSTS (sizeof(fund_consts)/sizeof(double)) 
>   then you can use stuff like:
>     extern fund_consts[N_FCONSTS];
>   elsewhere.

In recent years, i've often gone in precisely the other direction.
One of the hassles of large systems is the proliferation of names,
all looking very much alike.
You've just added another name (N_FCONSTS) for the programmer
to remember.

Admittedly the concept it embodied was tedious to type,
but it was quite derivable!

Try using 
	#define dim(a)	(sizeof(a)/sizeof(*(a)))
and you can elegantly express the size of any array.

it leads to such things as:
	for (i = 0; i < dim(fund_consts); i++)
		magic(i);
or
	p = buf;
	 ....
	while (p < &buf[dim(buf)])
		stuff(*p++);

where there is no question that the appropriate bound has been used.

Don't you always leave out a few letters when thinking up a name
to #define for a manifest constant? They all end up as N_THNGS & etc,
and tend to converge in a large project.

If the size of an array is a core concept, then it *should* have a name,
but if it's just a collection of like things, I like to keep the dimension
quite anonymous.

This can go to extremes, and sometimes I've been known to say:
	int things[200];		/* big enuff */
	int thungs[dim(things)+1];	/* one for each thing, plus sentinel */
all in order to avoid thinking of a new name.


all we need now is a typeof(lvalue) operator to complement sizeof(),
and i'd be happy!
-- 
Peter Swain                                       Softway Pty Ltd
swine@softway.oz.au                               PO Box 305
uunet!ccicpg!swine                                Strawberry Hills, NSW
                                                  Australia

tps@chem.ucsd.edu (Tom Stockfisch) (02/24/89)

In article <14647@ccicpg.UUCP> swine@ccicpg.UUCP (Peter Swain) writes:
>In article <807@atanasoff.cs.iastate.edu> hascall@atanasoff.cs.iastate.edu (John Hascall) writes:
>	[ .. week-long discussion deleted .. ]
>>>double fund_consts[] = {
>>>	3.14159265,
>>>};

>Try using 
>	#define dim(a)	(sizeof(a)/sizeof(*(a)))

This doesn't work unless the defining declaration of a[] is in the same file.
If it is in the same file, it probably should have been declared static.
Usually "a" must be declared in a header file which cannot have access to
the initialization.  The scheme I use is

	/* header.h */
	# define NELT 20
	extern int	a[NELT];

	/* extern.c */
	# include "header.h"
	int	a[] = { 42, 666, ... };
	/* compiler will complain if sizeof(a)/sizeof(a[0]) is not equal
	 * to NELT, thus ensuring that extern.c and header.h are in sync
	 */

Any file in the project can then get at the dimension of "a" by #include'ing
"header.h".  "extern.c" must NOT be

	int	a[NELT] = {...};

because if you delete a member of the initialization set, NELT becomes out
of sync without the compiler being able to complain.
-- 

|| Tom Stockfisch, UCSD Chemistry	tps@chem.ucsd.edu

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

>	int	a[] = { 42, 666, ... };

You forgot 23 :-)

>	/* compiler will complain if sizeof(a)/sizeof(a[0]) is not equal
>	 * to NELT, thus ensuring that extern.c and header.h are in sync
>	 */

No, it won't necessarily.  It'll complain if the list of initializers
contains *more* than NELT elements; however, if it contains *fewer*
elements, it'll just silently initialize the rest to 0.  If this is
acceptable, fine, but if you want to make sure you initialize it with
*exactly* NELT elements, you need more help than the compiler will give
you....