5.8. Arrays, the & operator and function

We have already emphasized that in most cases, the name of an array is converted into the address of its first element; one notable exception being when it is the operand of sizeof, which is essential if the stuff to do with malloc is to work. Another case is when an array name is the operand of the & address-of operator. Here, it is converted into the address of the whole array. What's the difference? Even if you think that addresses would be in some way ‘the same’, the critical difference is that they have different types. For an array of n elements of type T, then the address of the first element has type ‘pointer to T’; the address of the whole array has type ‘pointer to array of n elements of type T’; clearly very different. Here's an example of it:

int ar[10];
int *ip;
int (*ar10i)[10];       /* pointer to array of 10 ints */

ip = ar;                /* address of first element */
ip = &ar[0];            /* address of first element */
ar10i = &ar;            /* address of whole array */

Where do pointers to arrays matter? Not often, in truth, although of course we know that declarations that look like multidimensional arrays are really arrays of arrays. Here is an example which uses that fact, but you'll have to work out what it does for yourself. It is not common to do this sort of thing in practice:

int ar2d[5][4];
int (*ar4i)[4]; /* pointer to array of 4 ints */

for(ar4i= ar2d; ar4i < &(ar2d[5]); ar4i++)
      (*ar4i)[2] = 0; /* ar2d[n][2] = 0 */

More important than addresses of arrays is what happens when you declare a function that takes an array as an argument. Because of the ‘conversion to the address of its first element’ rule, even if you do try to pass an array to a function by giving its name as an argument, you actually end up passing a pointer to its first element. The usual rule really does apply in this case! But what if you declare that the function does have an argument whose type is ‘array of something’—like this:

void f(int ar[10]);

What happens? The answer may suprise you slightly. The compiler looks at that and says to itself ‘Ho ho. That's going to be a pointer when the function is called’ and then rewrites the parameter type to be a pointer. As a result, all three of these declarations are identical:

void f(int ar[10]);
void f(int *ar);
void f(int ar[]);       /* since the size of the array is irrelevant! */

Having seen that, your reaction might be to look for a solid object to bang your head against for a while, but we don't recommend it. Take a grip on yourself instead and put in the effort to work out:

Give that last one some thought. When you get to the bottom of it, you really will have grasped what arrays and pointers are about.