Like the parenthesis, the square brackets, '[' ']', must be used in nested balanced pairs. The square brackets are used only with arrays.
When an array is declared, the array identifier is followed by a pair of square brackets which contain a constant expression of integer type. The value of this constant expression is the number of elements in the array being declared:
int speed[5*20]; /* each of 100 elements are: int */ char dot[720][320]; /* each of 720 elements are: char [320] */
When an array is passed to a function, the leftmost index does not need to have the size specified because that information is not needed. This is because only the size of each element of the array is needed, and that is given by the type. In the second example above, the abstract type of each element in the "dot" array is: char [320]. Thus for a one dimensional array the effect is to pass a pointer to element type, while for a multidimensional array only the first can be left blank. Why this is will become clear when how an array element is accessed as described next.
Lastly, square brackets are used in an array selection expression. That is, an identifier previously declared to be an array is followed by a pair of square brackets with an integer expression within. The value of the expression selects the element of the array (from first which is element 0 to num_elements-1). When a multidimensional array is being used then there is one set of square bracket after another, one per dimension. In reality, the real meaning of a multidimensional array is: an array of arrays. From this view point, all arrays are one dimensional.
Actually the square bracket is a convenient shorthand notation for a pointer operation. The expression:
a[x]
means selects the x'th element of array 'a'. Internally, the compiler converts this into the following pointer expression:
(*(a+x))
where 'x' is implicitly multiplied by the size of the element in the array. Clearly the square bracket notation is much simpler.