Kodewick
Lesson 12 of 30Contents

2D arrays

Lesson 12 of 30 · Part 2 · Functions and arrays · about 15 minutes

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:

main.c
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}
Output
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 0Column 1Column 2Column 3
Row 080927568
Row 195889079
Row 260718593

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:

main.c
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}
Output
   1   2   3
   4   5   6

%4d gives each number 4 characters of room (lesson 3), so the columns line up.

Guess first

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}

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:

main.c
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}
Output
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.

main.c
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}
Output
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:

main.c
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}
Output
   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.

main.c
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}
Output
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.

Exercise 1

Add it all up

sales holds two weeks of sales, 7 days each. Work out the total for both weeks and print Total: 98.

It should print
Total: 98
exercise1.c
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}
Output
Press Run or Ctrl+Enter
Exercise 2

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.

It should print
   1   4
   2   5
   3   6
exercise2.c
1#include <stdio.h>2 3int main(void) {4    int m[2][3] = {{1, 2, 3}, {4, 5, 6}};5 6    return 0;7}
Output
Press Run or Ctrl+Enter
Exercise 3

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).

It should print
Highest 31: day 2, reading 3
exercise3.c
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}
Output
Press Run or Ctrl+Enter

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 at 0.
  • 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.