C++ Notes: Arrays as Pointers - Weird But True

Read Arrays as Pointers first.

Subscription is the equivalent of pointer arithmetic

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.

Differences between arrays and pointers

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.

& operator applied to arrays does nothing.

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

History?

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.