An array is a compound data object consisting of a particular number of one or more elements each of the same type - the base type of the array. This base type itself can be an elementary or compound type.
An array is declared and used with the square brackets operator. In a declaration, the expression in the square brackets must be a constant expression, as it specifies the number of elements in the array; e.g.:
char name[40]; unsigned int age[50*40]; /* 2000 elements */ double beam_height[5-2][8>>1]; /* 3 elements each a 4 element array */
The elements in an array are numbered from zero to the number minus 1. If the sizeof operator is applied, not to a type but to an array by name, then the value returned will be the number of elements times the size of the base type. To get the number of elements in the above arrays, one would write:
sizeof(name)/sizeof(char) sizeof(age)/sizeof(int) sizeof(beam_height)/sizeof(double [8>>1])
When an array is used in an expression one can use just the array name itself, which is type: pointer to the base type; e.g. age is a pointer to int. In particular it points to the first element, the one with an index of zero.
Or, one can use the square brackets as a selection operator to choose an element of the array, using an integer expression within the brackets to specify which element is being selected. Arrays are an efficient way to program similar calculations involving many elements. This method uses loops of some kind and is called iteration.
Such expressions are both lvalues and rvalues and may appear on either side of an assignment operator, as in the following examples:
a[x]=b[x]*c[x]; height[y+2]-=hole_depth; age[z]++;
Actually, the square brackets are an abbreviation for a pointer operation. This pointer operation involves the starting address of the array (which is what the array name has as value) and the value of the index. To be precise, the expression:
ary[x]
is identical to the pointer expression:
(*(ary+x))
where, as described above for pointers, the integer value, x in this case, added to a pointer is implicitly multiplied by the size of the base type of the array. Then the indirection operator, the unary asterisk, *, is applied to reference the selected entry in the array.
The extra parenthesis is to insure that the asterisk is not interpreted as the multiplication operator. This array-pointer equivalence formula is one of the most important ones in understanding how 'C' works. It is well worth what ever amount of time it takes to understand it.
An array can be an array of an array of something else, as was illustrated with the variable beam_height declared above. Such an array is called a two dimensional array. There is no inherent limit in the language to the number of dimensions that one can have.
In a multidimensional array, the elements that are sequential in memory are clearly those in which the right most index varies the fastest (e.g. with the others are held constant).
Let us see how a two dimensional array is converted into its equivalent pointer expression. Take the following declaration:
int two[200][34];
and the following use of that array:
two[z][w];
To be able to make the conversion, one must make the following algebraic substitution, let: B==two[z]. This gives us the equivalent expression:
int B[w];
which we know evaluates to:
(*(B+w))
Now, we take the equivalent expression for: B, i.e. two[z], which is:
(*(two+z))
and substitute, yielding:
(*((*(two+z))+w))
remembering that w is implicitly multiplied by: sizeof(int), and z is implicitly multiplied by: sizeof(int [34]), the base type of array two. This explains why when the right most index varies by one, and the others are held constant, adjacent element in memory are selected.