[comp.lang.c] Address of Arrays

rbutterworth@watmath.waterloo.edu (Ray Butterworth) (12/15/87)

Isn't it amazing how many people are confused by such a simple
concept as the address of an array?  If only K&R hadn't tried
to "optimize" out this idea, I don't think there would be any
of this confusion (at least no more than there is for the
concept of the address of a structure).

Anyway, one thing I like about this ability in modern versions of C
is for passing arguments to a function.  Often one passes in a
pointer to an array of some fixed size and it is nice to be able
to declare it this way and have lint check that it is correct in
the function.  e.g.

    func(buf, junk, stuff)
        int (*buf)[BUFDIM]; /* pointer to an array of 10 ints */
        int (*arr)[];       /* pointer to an array of ints */
        int *stuff;         /* pointer to an int */
        int no_work[4];     /* array of 4 ints (not true) */
    {
        *stuff = no_work[0] + (*arr)[0] + (*buf)[0];
    }

    main()
    {
        extern int buffer[BUFDIM];
        extern int array[27];
        extern int would_be_nice[4];
        auto int result;

        func(&buffer, &array, &result, would_be_nice);
        return result;
    }

Under K&R C, all four parameters would be declared as
"int *param;".  But with &array in the language, lint can
check that the first parameter was actually a pointer to an
array of the appropriate size and that the second was a pointer
to an array and not simply a pointer to a single int.

It also makes it more obvious to the programmer that for
"int *stuff;", stuff is a pointer to a single integer, while
"int (*arr)[];", arr is a pointer to an array of integers.

It is unfortunate that parameter "int no_work[4]" must be silently
turned into "int *no_work;", and the argument "would_be_nice" must
be silently turned into "&would_be_nice[0]" by the compiler.
That's one big step that I wish the ANSI people had taken.

Obviously there were too many objections on the ground that it
would break existing code in which parameter declarations
are made using array notation.  But since prototypes are new
and so don't affect existing code, they should at least have either
1) allowed prototypes of the form x[n] to be actual arrays
2) disallowed prototypes of the form x[] or x[n], so that future
   versions of the language could allow (1) without breaking
   anything.

(And if the "*" indirection operator could be used on the
 right instead of the left (as any sensible language would
 have it), we wouldn't need all those silly parentheses.
 e.g. "int x*[]" pointer to an array of ints, y = x*[2];
 e.g. "int x[]*" array of pointers to ints,   y = x[2]*;
 would be so much simpler. :-)

karl@haddock.ISC.COM (Karl Heuer) (12/17/87)

In article <15869@watmath.waterloo.edu> rbutterworth@watmath.waterloo.edu (Ray Butterworth) writes:
>Anyway, one thing I like about this ability in modern versions of C
>is for passing arguments to a function [which can then be typechecked].

I'm glad someone mentioned this.  One good example is setjmp(), which really
ought to take the address of a jmp_buf (rather than the value) as argument.

>But since prototypes are new and so don't affect existing code, they should
>at least have either
>1) allowed prototypes of the form x[n] to be actual arrays
>2) disallowed prototypes of the form x[] or x[n], so that future
>   versions of the language could allow (1) without breaking anything.

Exactly what Mark Brader and I have been saying.  Unfortunately, I think the
good people at X3J11 have determined (probably correctly) that (1) is too much
work at this point, and have overlooked the benefits of (2).  (Or, more
precisely, overlooked the costs of not doing (2).)

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