Opening the reading…
Opening the reading…
PROGRAMMING FUNDAMENTALS › C++ FUNDAMENTALS
A two-dimensional array is an array whose elements are themselves arranged in rows. In int marks[2][3], the first bracket says there are 2 rows, and the second says each row contains 3 integers. This gives 2 * 3, or 6, elements. The dimensions describe different parts of the layout, so they are not interchangeable.
int marks[2][3] = {
{4, 2, 7},
{1, 5, 3}
};The nested braces make the row structure visible. The first inner brace initializes row 0 with 4, 2, and 7. The second inner brace initializes row 1 with 1, 5, and 3. The array is not six values with two labels that can be swapped. It is two separate rows, each with three columns.
To select an element, write the row index first and the column index second. In marks[0][2], 0 selects row 0, which is 4, 2, 7, and 2 selects the third column, whose value is 7. In marks[1][1], 1 selects row 1, and the column index 1 selects its second value, 5.
int firstValue = marks[0][2]; // 7
int secondValue = marks[1][1]; // 5The row index has the valid range 0-1 because there are 2 rows. The column index has the independent valid range 0-2 because each row has 3 columns. An expression such as marks[2][0] does not mean column 2 and row 0. It asks for row 2, which does not exist, so accessing it is undefined behavior in C++.
Which expression selects the value 7 from marks?
Checkpoints are not graded. They are here so you catch yourself before the quiz does — stuck, ask the tutor on the right.
One loop can choose a row, but it cannot by itself visit all three columns in that row. A nested loop solves this by letting the outer loop select rows and the inner loop select columns. The outer loop uses the row count, 2. For each row, the inner loop uses the column count, 3.
for (int row = 0; row < 2; row++) {
for (int column = 0; column < 3; column++) {
cout << marks[row][column] << ' ';
}
}The visits occur in this order: 4, 2, 7, 1, 5, 3. The inner loop finishes all three columns of row 0 before the outer loop moves to row 1. The loop limits must match their dimensions. Using 3 as the row limit asks for row 2 after rows 0 and 1, while using 2 as the column limit skips column 2 from every row.
The six integers appear in memory in row order: 4, 2, 7, 1, 5, 3. The three values of row 0 come first, followed immediately by the three values of row 1. This is called row-major layout. A row is consecutive because the array must know how many columns to skip whenever it moves to the next row.
For this array, the offset of marks[row][column] is row * 3 + column. The multiplier is 3 because every complete row contains 3 integers. For marks[1][1], the calculation is 1 * 3 + 1 = 4, so the element is at offset 4 in the flattened order, where its value is 5.
Replace both question marks so the two expressions identify the value 5 in marks and its flattened offset.
marks[?][?]
row * 3 + columnCheckpoints are not graded. They are here so you catch yourself before the quiz does — stuck, ask the tutor on the right.
When this array is passed to a function, the parameter must preserve the number of columns. You can write the parameter as const int marks[][3] and pass the row count separately as 2. C++ allows the first extent to be omitted in this parameter form because the function receives access to the existing array, but it still needs the column extent.
void printMarks(const int marks[][3], int rows) {
for (int row = 0; row < rows; row++) {
for (int column = 0; column < 3; column++) {
cout << marks[row][column] << ' ';
}
cout << '\n';
}
}The function uses the column extent to calculate each element's location. To reach marks[row][column], it skips row complete rows, with 3 integers in each row, and then moves column positions inside the selected row. If the parameter used 2 as its column extent, the function would calculate offsets for a different layout and would not correctly describe marks[2][3].