2D arrays
Three students, four tests each. Data like this is naturally a table: one row per student, one column per test. C keeps it in a 2D array:
1#include <stdio.h>2 3int main(void) {4 int scores[3][4] = {5 {80, 92, 75, 68},6 {95, 88, 90, 79},7 {60, 71, 85, 93}8 };9 printf("Student 1, test 1: %d\n", scores[0][0]);10 printf("Student 3, test 4: %d\n", scores[2][3]);11 return 0;12}
Student 1, test 1: 80 Student 3, test 4: 93
int scores[3][4] has 3 rows and 4 columns: 12 int values in all. Each inner pair of curly braces is one row. To get an element you write two indexes: the row first, then the column. Both start at 0:
| Column 0 | Column 1 | Column 2 | Column 3 | |
|---|---|---|---|---|
| Row 0 | 80 | 92 | 75 | 68 |
| Row 1 | 95 | 88 | 90 | 79 |
| Row 2 | 60 | 71 | 85 | 93 |
Nested loops
The outer loop goes over the rows, and the inner loop goes over the columns of that row. After each row, start a new line. Press Step and watch how row and col change together:
1#include <stdio.h>2 3int main(void) {4 int grid[2][3] = {5 {1, 2, 3},6 {4, 5, 6}7 };8 for (int row = 0; row < 2; row++) {9 for (int col = 0; col < 3; col++) {10 printf("%4d", grid[row][col]);11 }12 printf("\n");13 }14 return 0;15}
1 2 3 4 5 6
%4d gives each number 4 characters of room (lesson 3), so the columns line up.
What does this print?
1#include <stdio.h>2 3int main(void) {4 int g[3][2] = {5 {1, 2},6 {3, 4},7 {5, 6}8 };9 printf("%d\n", g[1][0]);10 return 0;11}
g[1] is the second row, {3, 4}, and g[1][0] is the first element of that row: 3. Row first, then column.
Row totals
A student's total is one row added up. For each new row, total has to start again at 0, so it is declared inside the outer loop:
1#include <stdio.h>2 3int main(void) {4 int scores[3][4] = {5 {80, 92, 75, 68},6 {95, 88, 90, 79},7 {60, 71, 85, 93}8 };9 for (int s = 0; s < 3; s++) {10 int total = 0;11 for (int c = 0; c < 4; c++) {12 total += scores[s][c];13 }14 printf("Student %d: total %d, average %.2f\n", s + 1, total, total / 4.0);15 }16 return 0;17}
Student 1: total 315, average 78.75 Student 2: total 352, average 88.00 Student 3: total 309, average 77.25
Column averages
A test's average needs one column added up. This time it's the other way around: the outer loop goes over the columns, the inner loop over the rows.
1#include <stdio.h>2 3int main(void) {4 int scores[3][4] = {5 {80, 92, 75, 68},6 {95, 88, 90, 79},7 {60, 71, 85, 93}8 };9 for (int c = 0; c < 4; c++) {10 int total = 0;11 for (int s = 0; s < 3; s++) {12 total += scores[s][c];13 }14 printf("Test %d: average %.1f\n", c + 1, total / 3.0);15 }16 return 0;17}
Test 1: average 78.3 Test 2: average 83.7 Test 3: average 83.3 Test 4: average 80.0
The element is still scores[s][c], row first. All that changed is which loop is on the outside.
Adding matrices
In math, a table of numbers is called a matrix. Adding two matrices of the same size means adding the numbers in the same spot. Say two shops sold three kinds of fruit over two days; adding their tables gives the total sales:
1#include <stdio.h>2 3int main(void) {4 int shopA[2][3] = {{5, 3, 8}, {6, 2, 7}};5 int shopB[2][3] = {{4, 9, 1}, {3, 5, 2}};6 int sum[2][3];7 for (int r = 0; r < 2; r++) {8 for (int c = 0; c < 3; c++) {9 sum[r][c] = shopA[r][c] + shopB[r][c];10 }11 }12 for (int r = 0; r < 2; r++) {13 for (int c = 0; c < 3; c++) {14 printf("%4d", sum[r][c]);15 }16 printf("\n");17 }18 return 0;19}
9 12 9 9 7 9
sum starts out unassigned. The first pair of loops fills all 6 cells, and the second pair prints them.
How it sits in memory
Memory is one long strip, with no rows or columns. A 2D array is really stored row after row: all of row 0 first, then row 1. So grid[2][3] is 6 int values in a row, and grid[0] is one row of 3 int values.
1#include <stdio.h>2 3int main(void) {4 int grid[2][3] = {{1, 2, 3}, {4, 5, 6}};5 int rows = sizeof grid / sizeof grid[0];6 int cols = sizeof grid[0] / sizeof grid[0][0];7 printf("Whole: %zu bytes\n", sizeof grid);8 printf("One row: %zu bytes\n", sizeof grid[0]);9 printf("%d rows, %d columns\n", rows, cols);10 return 0;11}
Whole: 24 bytes One row: 12 bytes 2 rows, 3 columns
Just like a 1D array, sizeof tells you how many rows there are and how many columns each has. And each index must stay in bounds too: grid[0][3] sits right next to grid[1][0] in memory, but it is still out of bounds, and the engine stops.
Tip: Values you don't give are 0, so int table[3][4] = {0}; sets the whole table to zero.
Practice
Write the code, then press Check. A hint costs nothing; the answer is there when you need it.
Add it all up
✓sales holds two weeks of sales, 7 days each. Work out the total for both weeks and print Total: 98.
Total: 98
1#include <stdio.h>2 3int main(void) {4 int sales[2][7] = {5 {5, 8, 6, 7, 9, 12, 4},6 {6, 7, 5, 8, 10, 7, 4}7 };8 9 return 0;10}
Turn it around
✓Print the 2-row, 3-column m as 3 rows and 2 columns: column 0 becomes row 0, and so on. Print each number with %4d.
1 4 2 5 3 6
1#include <stdio.h>2 3int main(void) {4 int m[2][3] = {{1, 2, 3}, {4, 5, 6}};5 6 return 0;7}
The hottest moment
✓temps holds temperatures for 3 days, taken 4 times a day. Find the highest one and where it is, and print Highest 31: day 2, reading 3 (days and readings count from 1).
Highest 31: day 2, reading 3
1#include <stdio.h>2 3int main(void) {4 int temps[3][4] = {5 {18, 24, 27, 20},6 {19, 26, 31, 22},7 {17, 23, 29, 21}8 };9 10 return 0;11}
What you learned
- A 2D array is like a table:
int a[3][4]has 3 rows and 4 columns, and each inner pair of braces is a row. - An element takes two indexes, row first:
a[row][col], both starting at0. - Loop over it with nested loops: rows outside, columns inside. To work by column, put the columns outside.
- Adding matrices: add the numbers in the same spot and put them in a third array.
- In memory it's stored row after row;
sizeof a / sizeof a[0]is the number of rows,sizeof a[0] / sizeof a[0][0]the number of columns.