When you truly understand the following remarkable equivalence,
you will understand the equivalence of arrays and pointers.
Assume a
is an array and i
is an integer.
a[i] == *(a + i) == *(i + a) == i[a]
Altho these are equivalent, never, ever, write i[a]
instead of a[i]
.
I've never seen C's predecessor B, but have seen another of B's descendants, BCPL, which used pointers and no subscription as I remember. So I assume that the first versions of C had no subscription - only pointer operations, which would explain this amazing equivalence.
Never write subscripts in the inverted form.
sum = sum + a[i]; // good sum = sum + i[a]; // legal, but horrible style char hexDigit = "0123456789ABCDEF"[i]; // good char hexDigit = i["0123456789ABCDEF"]; // legal, but horrible style
Program entries in the annual C Obfuscation contest actually do something, but are written so as to obscure their behavior. Reversing the subscript and array could be a useful technique for the contest, but not for writing good programs.
Having said that arrays and pointers are basically the same, I must admit that there are some differences. The only differences I'm aware of are the following. These only apply to the function that the array is declared it -- if an array is passed as a parameter, even if the parameter is declared as an array, it's treated exactly like a pointer.
&
) does nothing when applied to array names (see discussion below),
but does with pointers..const
.sizeof
operator returns the size of the allocated space for
actual arrays, but not array parameters (ie, where the size can be computed at compile-time).The & (address of) operator normally returns the address of
the operand. However, arrays are the exception.
When applied to an array (which is an address), it has the
same value as the array reference without the operator.
This isn't true of the equivalent pointers, which have an
independent address. The example below show this.
When cout
is given an address, it prints it
in hexadecimal (except addresses of characters, which are
assumed to be the beginning of a c-string).
For example,
// arrayptr.cpp - Show operation of & on arrays and pointers. // Fred Swartz - 2002-09-25 #include <iostream> using namespace std; int main() { double a[100]; // array double* p = a; // pointer equivalent to a cout << "a=" << a << ", &a=" << &a << endl; cout << "p=" << p << ", &p=" << &p << endl; return 0; }
This produces the following output showing the unexpected equality a == &a
.
The value of p
is the same as a
as expected, and
&p
is the address of the memory location of the p variable as
expected.
a=006AFAD8, &a=006AFAD8 p=006AFAD8, &p=006AFAD4
I don't know the history of this bit of C weirdness, but suspect it was added because the scanf() function, the mainstay of C input, requires the address of the variables to put things into. So a function call might look like.
int a, b, d, f; char c[100];
scanf("some format here", &a, &b, c, &d, &f); // Very correct.
Hmmm, why does everthing except the character string c require an &? Answer: it's an array and an array name is the address of the associated memory. So it would appear more consistent to allow the &, and I suppose many early users wrote this (certainly many students do without knowing what it might mean). What would happen if they weren't equivalent and the user naively wrote the following?
scanf("some format here", &a, &b, &c, &d, &f); // Correct.
With the & in front of c, if the compiler really took the address of c, input would overwrite part of call stack with disasterous consequences. So I suspect they eliminated this problem by making c and &c mean the same thing. Ugly, but only one of the many C warts.