2-D Arrays & Arrays in Functions
Tables of valuesA 2-D array is a table: rows and columns, reached with two indexes, m[row][column]. In the lab below you see the table you imagine next to the single row of memory C really uses, find out why a function can change an array you pass to it, and multiply two matrices cell by cell.
- m[2][3]2 rows, 3 columns
- Row-majorrow 0, then row 1 … in memory
- f(arr)passes the address, not a copy
Ready
Keyboard: ← → step · Space play / pause · R reset · Esc exit classroom mode
The ideas behind the lab
Exactly what you watched happen, in plain steps.
A table stored as one row
int m[2][3] is an array of 2 rows, and each row is an array of 3 ints. You use it like a table — m[row][column] — but memory is a single line, so C stores row 0 first, then row 1 (row-major order). When you pass any array to a function, C passes the address of its first element: the function works on the caller's cells, not on a copy, and it needs the size as an extra parameter.
int m[2][3] = {{1, 2, 3},
{4, 5, 6}};
// m[1][2] is 6: row 1, column 2
// memory: 1 2 3 4 5 6 → m[i][j] is element i * 3 + j
void show(int m[][3], int rows); // 2-D: the column count is required
int sum(const int a[], int n); // 1-D: the size comes separately
| Element | Value | Position in memory | Address |
|---|---|---|---|
| m[0][0] | 1 | 0 × 3 + 0 = 0 | 0x1000 |
| m[0][2] | 3 | 0 × 3 + 2 = 2 | 0x1008 |
| m[1][0] | 4 | 1 × 3 + 0 = 3 | 0x100c |
| m[1][1] | 5 | 1 × 3 + 1 = 4 | 0x1010 |
| m[1][2] | 6 | 1 × 3 + 2 = 5 | 0x1014 |
2-D arrays
- type name[rows][columns]; — the first index is the row, the second the column.
- Initialise row by row: {{1, 2, 3}, {4, 5, 6}}; missing values become 0.
- The row count may be left out: int m[][3] = {…}; — the column count may not.
- Nested loops: the outer loop over rows (i), the inner over columns (j).
- Row-major memory: m[i][j] sits at position i × columns + j.
Arrays and functions
- f(arr) sends the address of arr[0] — the array is never copied.
- So the function can change the caller's elements.
- Inside, sizeof cannot tell the length: pass the size as another parameter.
- Write const int a[] when the function must only read the array.
- For 2-D arrays the column count must be in the parameter: int m[][3].
Matrix operations
- Addition: C[i][j] = A[i][j] + B[i][j] — the same size needed.
- Transpose: T[j][i] = M[i][j] — rows become columns.
- Multiplication: C[i][j] = sum over k of A[i][k] × B[k][j].
- A (r × n) times B (n × c) gives r × c: the inner sizes must match.
- Matrix multiplication is not commutative: A × B is usually not B × A.
Row sums in a function, and a transpose
Every line, explained.
#include <stdio.h>
#define R 2
#define C 3
void printRowSums(int m[][C], int rows)
The column count is part of the parameter type.
{
for (int i = 0; i < rows; i++) {
int sum = 0;
A fresh sum for every row.
for (int j = 0; j < C; j++)
sum += m[i][j];
printf("row %d: %d\n", i, sum);
Prints row 0: 6 and row 1: 15
}
}
int main(void)
{
int m[R][C] = {{1, 2, 3}, {4, 5, 6}};
int t[C][R];
The transpose is 3 × 2.
for (int i = 0; i < R; i++)
for (int j = 0; j < C; j++)
t[j][i] = m[i][j];
Swap the indexes.
printRowSums(m, R);
Only the address of m is passed.
printf("t[2][1] = %d\n", t[2][1]);
t[2][1] = m[1][2]: prints 6
return 0;
}
Spot the bug
Mistakes almost every beginner makes — and how to fix them.
Swapping rows and columns
int m[2][3]; m[2][1] = 5; // there is no row 2
int m[2][3]; m[1][2] = 5; // row 1, column 2
The first index is the row (0–1 here), the second the column (0–2).
m[i, j] instead of m[i][j]
x = m[1, 2];
x = m[1][2];
Inside [ ] the comma is the comma operator: m[1, 2] means m[2] — a whole row.
Leaving out the column count
void show(int m[][], int r);
void show(int m[][3], int r);
To find m[i][j] the compiler must know the row length (i × columns + j).
Using sizeof on an array parameter
int sum(int a[]) {
int n = sizeof a / sizeof a[0]; // wrong
…
int sum(const int a[], int n) { … }
In a function a is only an address, so sizeof a is the size of a pointer. Pass the length.
Not resetting a per-row total
int sum = 0;
for (i …) { for (j …) sum += m[i][j];
printf("%d", sum); }
for (i …) { int sum = 0;
for (j …) sum += m[i][j];
printf("%d", sum); }
Without a fresh sum each row, the second row's total includes the first.
Check your understanding
Answer each question — you will see the explanation straight away.
int m[3][4]; — how many ints does it hold?
3 rows × 4 columns.
int m[2][3] = {{1, 2, 3}, {4, 5, 6}}; — what is m[1][0]?
Row 1, column 0.
In int m[2][3], which element comes right after m[0][2] in memory?
Row-major: after the end of row 0 comes the start of row 1.
void z(int a[], int n) { a[0] = 0; } — int v[2] = {5, 6}; z(v, 2); What is v[0]?
The function works on the caller's array through its address.
A is 2 × 3 and B is 3 × 4. What size is A × B?
The inner sizes (3) match; the result takes the outer sizes.
2-D Arrays & Arrays in Functions quiz
Test yourself: 10 questions, 70% to pass. Create a free account to take the quiz, save your progress and work towards the certificate.