[comp.lang.c] Array pointers

guy@gorodish.UUCP (02/27/87)

(This has drifted away from UNIX issues and towards C issues.)

>>main (argc, argv)
>>int argc; 
> vvvvvvvvvvvv
>>char **argv;
> ^^^^^^^^^^^^
>>{
>> ...
>>	if((f1 = fopen(argv[1], "r")) == NULL )

>You really shouldn't have declared char **argv if you want to treat
>argv as an array.

But "argv" *I*S*N'*T* an array.  It's a pointer to the first element
of an array.  To be precise, it's a pointer to the first element of
an array of pointers to "char", which is why it has type "char **".

>Instead, change that declaration to *argv[]

Since "argv" is a parameter, the compiler will interpret a parameter
declaration like "char *argv[]" as "char **argv".  K&R, Page 205:

	Also, since a reference to an array in any context (in
	particular as an actual parameter) is taken to mean a pointer
	to the first element of the array, declarations of formal
	parameters declared ``array of ...'' are adjusted to read
	``pointer to ...''.

October 1, 1986 ANSI C draft, page 71:

	Because array expressions and function designators as
	arguments are always converted to pointers before the call, a
	declaration of a formal parameter as ``array of *type*''
	shall always be adjusted to ``pointer to *type''...

>I suspect that C doesn't treat arrays of pointers exactly as it treats
>pointers to pointers, but I'm not really that sharp on the subject.

That's true, except that you can't declare formal parameters of type
array (see above), so in this case, unfortunately, it *does* sort-of
treat them the same.  (I wish it hadn't, given all the confusion it
seems to cause.)  However, in most situations array-valued
expressions are converted to pointer-valued expressions that point to
the first element of the array in question (another source of
confusion), so they are often treated very similarly.

>Some C compilers will give you "type mismatch" errors when you define a
>pointer value and then reference it as an array.

No program that gives a "type mismatch" on something like

	...
	char **argv;
	{
		...

		if ((fp = fopen(argv[1])) == NULL) {
			...

is a C compiler.  It may be a compiler for a language resembling C,
but it's not a compiler for C.  The C subscripting operator does
*not* apply to arrays at all; it *only* applies to pointers.  "a[i]"
is defined to mean "*(a + i)".  K&R, page 210:

	...By definition, the subscript operator [] is interpreted in
	such a way that E1[E2] is identical to *((E1)+(E2)).

The October 1, 1986 ANSI C draft says the same thing (in almost the
exact same language) on page 32.

The reason this works on arrays is that array-valued expressions are,
except in a few circumstances, converted to pointer-valued
expressions that point to the first element of that array-valued
expression.  As such, if you declare "int foo[32]", the
sub-expression "foo" of the expression "foo[8]" is converted to a
pointer to the first element of "foo".  This means that converting
"foo[8]" to "*(foo + 8)" is valid.  8 is added to the pointer-valued
expression in question, yielding a pointer-valued expression that
points to an "int" 8 elements further into the array than the one
pointed to by the pointer-valued expression that "foo" is converted
to.  Since the latter expression points to the first element, the
former expression points to the ninth element (remember, C arrays are
0-origin arrays, so the Nth element is "array[N-1]").  Then "*(foo + 8)"
refers to the element of the array pointed to by that pointer-valued
expression, namely the ninth element.

Please, people, if you're going to make a claim that some proposition
X about the C language or some piece of C code is true, be certain
that this claim can be justified by some bit of K&R, H&S, the ANSI
draft standard, or something like that before posting.