array
sYou can use array
s with two dimensions (i.e., subscripts) to represent tables of values consisting of information arranged in rows and columns. To identify a particular table element, we must specify two subscripts—by convention, the first identifies the element’s row and the second identifies the element’s column. array
s that require two subscripts to identify a particular element are called two-dimensional array
s or 2-D array
s. array
s with two or more dimensions are known as multidimensional array
s. Figure 7.16 illustrates a two-dimensional array
, a
. The array
contains three rows and four columns, so it’s said to be a 3-by-4 array
. In general, an array
with m rows and n columns is called an m-by-narray
.
Every element in array
a
is identified in Fig. 7.16 by an element name of the form a[i][j]
, where a
is the name of the array
, and i
and j
are the subscripts that uniquely identify each element in a
. Notice that the names of the elements in row 0 all have a first subscript of 0
; the names of the elements in column 3 all have a second subscript of 3
.
Referencing a two-dimensional array
element a[x][y]
incorrectly as a[x,
y]
is an error. Actually, a[x,
y]
is treated as a[y]
, because C++ evaluates the expression x, y
(containing a comma operator) simply as y
(the last of the comma-separated expressions).
Figure 7.17 demonstrates initializing two-dimensional array
s in declarations. Lines 12–13 each declare an array
of array
s with two rows and three columns. Notice the nested array
type declaration. In each array
, the type of its elements is specified as
array<int, columns>
indicating that each array
contains as its elements three-element array
s of int
values— the constant columns
has the value 3.
The declaration of array1
(line 12) provides six initializers. The compiler initializes the elements of row 0 followed by the elements of row 1. So, the first three values initialize row 0’s elements to 1, 2 and 3, and the last three initialize row 1’s elements to 4, 5 and 6. The declaration of array2
(line 13) provides only five initializers. The initializers are assigned to row 0, then row 1. Any elements that do not have an explicit initializer are initialized to zero, so array2[1][2]
is 0.
The program calls function printArray
to output each array
’s elements. Notice that the function prototype (line 9) and definition (lines 23–33) specify that the function receives a two-row and three-column array
. The parameter receives the array
by reference and is declared const
because the function does not modify the array
’s elements.
for
StatementsTo process the elements of a two-dimensional array
, we use a nested loop in which the outer loop iterates through the rows and the inner loop iterates through the columns of a given row. Function printArray
’s nested loop is implemented with range-based for
statements. Lines 25 and 27 introduce the C++11 auto
keyword, which tells the compiler to infer (determine) a variable’s data type based on the variable’s initializer value. The outer loop’s range variable row
is initialized with an element from the parameter a
. Looking at the array
’s declaration, you can see that the array
contains elements of type
array<int, columns>
so the compiler infers that row
refers to a three-element array
of int
values (again, columns
is 3). The const&
in row
’s declaration indicates that the reference cannot be used to modify the rows and prevents each row from being copied into the range variable. The inner loop’s range variable element
is initialized with one element of the array
represented by row
, so the compiler infers that element
refers to an int
because each row contains three int
values. In an IDE, you can typically hover your mouse over a variable declared with auto
and the IDE will display the variable’s inferred type. Line 28 displays the value from a given row and column.
for
StatementsWe could have implemented the nested loop with counter-controlled iteration as follows:
for (size_t row{0}; row < a.size(); ++row) {
for (size_t column{0}; column < a[row].size(); ++column) {
cout << a[row][column] << ' ';
}
cout << endl;
}
array
ManipulationsThe following for
statement sets all the elements in row 2 of array
a
in Fig. 7.16 to zero:
for (size_t column{0}; column < 4; ++column) {
a[2][column] = 0;
}
The for
statement varies only the second subscript (i.e., the column subscript). The preceding for
statement is equivalent to the following assignment statements:
a[2][0] = 0;
a[2][1] = 0;
a[2][2] = 0;
a[2][3] = 0;
The following nested counter-controlled for
statement determines the total of all the elements in array
a
in Fig. 7.16:
total = 0;
for (size_t row{0}; row < a.size(); ++row) {
for (size_t column{0}; column < a[row].size(); ++column) {
total += a[row][column];
}
}
The for
statement totals the elements of the array
one row at a time. The outer for
statement begins by setting row
(i.e., the row subscript) to 0
, so the elements of row 0 may be totaled by the inner for
statement. The outer for
statement then increments row
to 1
, so the elements of row 1 can be totaled. Then, the outer for
statement increments row
to 2
, so the elements of row 2 can be totaled. When the nested for
statement terminates, total
contains the sum of all the array
elements. This nested loop can be implemented with range-based for statements as:
total = 0;
for (auto row : a) { // for each row
for (auto column : row) { // for each column in row
total += column;
}
}