Suppose that, because of your growing reputation as an expert with computers, you have been asked to assist the local little theatre group in maintaining records of seats sold for their upcoming play. The auditorium that the group uses has twenty-five rows, each of which contain thirty seats. To keep track of sales, it would be useful to have an array of boolean values in which an element has the value true if and only if the seat has been sold.
Sales of seats in a single row could be monitored using a boolean array of size thirty. This could be declared with the statement
boolean[] row = new boolean [30];
to produce the following result.
To monitor sales for the entire auditorium, we want one of these arrays for each row. We can do this easily by writing
boolean[][] sold = new boolean[25][30];
The results of this declaration are shown in the next diagram.
Although this may be surprising at first, analysis may make it seem perfectly reasonable. Recall that the general form of a declaration of an array was
<type>[] <identifier> = new <type>[<expression>];
Comparing this form with our declaration of the sold array, the <type> of the components of sold is boolean[]; each element of the sold array is of type boolean[], a reference to an array of boolean values. As the diagram indicates, the identifiers ofthese references are sold[O] , sold[1], ... , sold[24].
Each sold[i] value refers to a boolean array, each of whose elements are initialized to false (indicated by the letter f in the diagram). The elements of the boolean arrays are identified by two indices - the first for the index of the array reference and the second for the index of the element within its array. For example, the element in the upper left hand corner of the diagram has identifier sold[O][0] while the element in the lower right hand corner has identifier sold[24][29].
We could have created this structure in stages. As a first step, we could have written
boolean[][] sold = new boolean[25][];
to create sold, a reference to an array of 25 variables of type boolean []. As usual, when we create a new array, the values are initialized. Since the type of the values is a reference type, each one is initialized to null.
Now, to create the arrays to represent each row, we can use a loop.
for(int i = 0; i < sold. length; i++) sold[i] = new boolean [30];
The loop would be executed 25 times (the value of sold.length). Each time around, one more array of 30 elements would be generated and initialized. The final result would be what we want: 25 arrays of 30 boolean elements representing the seats sold in the auditorium. An array of arrays like this one is known as a two-dimensional array.
Often, we want to use two-dimensional arrays to represent values in a simple rectangular table. In such cases, we can think of a two-dimensional array as consisting of rows and columns. If we do this, it is customary to think of the index representing a row preceding that representing a column.
|
Just as for statements are usually used to index through a one-dimensional array, nested for statements are usually used to index through a two-dimensional array. For the array table shown in Example 1 we can initialize the elements to one using the following fragment.
for (int row = 0; row < table.length; row++) for (int col = 0; col < table [0].length; col++) table[row][col] = 1;
Notice the way in which the upper bounds of the loops are written. The number of rows in table is given by table.length while the number of columns in row zero (and all other rows) is given by table[0].length.
Two-dimensional arrays can be initialized as they are being declared, in a manner similar to that used for one-dimensional arrays.
|
The one-dimensional arrays that compose a two-dimensional array need not all be of the same length, as the next example illustrates.
|
Array declarations like the one for triTable in Example 3, in which the second dimension's size was unspecified, are legal. However, it is not legal to have the first dimension's size unspecified. For example, the declaration
int[][] badArray = new int[][20];
is not permitted.
Non-rectangular two-dimensional arrays are sometimes called ragged arrays. We can initialize ragged arrays in their declarations, just as we did for rectangular arrays.
|
To process the elements of a ragged array, we must change our loop structure slightly to take account of the fact that the length of each row may be different.
|
Multi-dimensional arrays are not limited to two dimensions. We can create three-dimensional arrays, four-dimensional arrays, or arrays of even higher dimensions. These higher-dimensional arrays are usually rectangular, but they need not be. We suggested that a two-dimensional rectangular array could be visualized as a table with rows and columns. Similarly, a rectangular three-dimensional array can be visualized as a set of tables, perhaps a book containing a number of tables, one on each page. The indices could then be thought of as representing the pages, rows, and columns (in that order). A four-dimensional array could then be thought of as a number of volumes of books, all of the same size, with an index specifying a volume, page, row, and column. As with two-dimensional arrays, we need not specify all the dimensions in a declaration of a higher-dimensional array.
|
|
Finally, we note that, just as one-dimensional array references can be used as parameters and return values of methods, so too can multidimensional array references. Of course, the dimensions of arguments and parameters must match and their types must be appropriate. It is also possible to pass sub-arrays to methods, as the next example illustrates.
|
|