Matrices aren’t just grids of numbers — they’re the language of linear algebra, powering everything from video games to AI neural networks. Let’s learn matrix multiplication from the ground up.
A matrix is a rectangular array of numbers arranged in rows and columns. An $m \times n$ matrix has $m$ rows and $n$ columns.
\[A = \begin{bmatrix} 1 & 2 \\ 3 & 4 \\ 5 & 6 \end{bmatrix} \quad \text{(a 3×2 matrix)}\]Before multiplying matrices, you need to understand the dot product.
Given two vectors of the same length, the dot product multiplies corresponding entries and sums them:
\[\vec{a} \cdot \vec{b} = a_1b_1 + a_2b_2 + \cdots + a_nb_n\]For example: \(\begin{bmatrix} 1 & 2 & 3 \end{bmatrix} \cdot \begin{bmatrix} 4 \\ 5 \\ 6 \end{bmatrix} = 1(4) + 2(5) + 3(6) = 4 + 10 + 18 = 32\)
To multiply $A \times B$:
![]()
Image: Each cell in the result is the dot product of a row from the first matrix and a column from the second.
#include <stdio.h>
#include <stdlib.h>
/*
* Matrix Multiplication in C
* A[m][k] × B[k][n] = C[m][n]
*/
#define ROW_A 3
#define COL_A 2
#define ROW_B 2
#define COL_B 3
// Function to multiply two matrices
int** multiply_matrices(int A[][COL_A], int B[][COL_B]);
int main() {
// Matrix A: 3 rows, 2 columns
int A[ROW_A][COL_A] = {
{1, 2},
{3, 4},
{5, 6}
};
// Matrix B: 2 rows, 3 columns
// Note: COL_A (2) must equal ROW_B (2) ✓
int B[ROW_B][COL_B] = {
{1, 2, 3},
{4, 5, 6}
};
printf("Matrix A (%dx%d):\n", ROW_A, COL_A);
for (int i = 0; i < ROW_A; i++) {
for (int j = 0; j < COL_A; j++) {
printf("%d\t", A[i][j]);
}
printf("\n");
}
printf("\nMatrix B (%dx%d):\n", ROW_B, COL_B);
for (int i = 0; i < ROW_B; i++) {
for (int j = 0; j < COL_B; j++) {
printf("%d\t", B[i][j]);
}
printf("\n");
}
// Multiply!
int **C = multiply_matrices(A, B);
printf("\nResult C = A × B (%dx%d):\n", ROW_A, COL_B);
for (int i = 0; i < ROW_A; i++) {
for (int j = 0; j < COL_B; j++) {
printf("%d\t", C[i][j]);
}
printf("\n");
}
// Free allocated memory
for (int i = 0; i < ROW_A; i++) {
free(C[i]);
}
free(C);
return 0;
}
int** multiply_matrices(int A[][COL_A], int B[][COL_B]) {
// Allocate result matrix C[ROW_A][COL_B]
int **C = (int**)malloc(ROW_A * sizeof(int*));
for (int i = 0; i < ROW_A; i++) {
C[i] = (int*)malloc(COL_B * sizeof(int));
}
// Triple nested loop for matrix multiplication
for (int i = 0; i < ROW_A; i++) { // rows of A
for (int j = 0; j < COL_B; j++) { // columns of B
C[i][j] = 0; // initialize cell
// Compute dot product of row i of A and column j of B
for (int k = 0; k < COL_A; k++) { // COL_A == ROW_B
C[i][j] += A[i][k] * B[k][j];
}
}
}
return C;
}
Matrix A (3x2): 1 2 3 4 5 6 Matrix B (2x3): 1 2 3 4 5 6 Result C = A × B (3x3): 9 12 15 19 26 33 29 40 51
Let’s verify one cell: $C_{0,0} = (1 \times 1) + (2 \times 4) = 1 + 8 = 9$ ✓
The function returns int** (a pointer to pointers) because C needs to allocate the result matrix dynamically on the heap. The stack can’t easily return 2D arrays.
| Mistake | Why It Breaks |
|---|---|
| $A_{cols} \neq B_{rows}$ | Dimensions must match for multiplication |
Forgetting to malloc |
Dangling pointer → crash |
| Not freeing memory | Memory leak |
| Wrong loop order | Wrong result or out-of-bounds access |
The identity matrix $I$ is the "1" of matrix multiplication.
\[A \times I = A\]// 4x4 Identity Matrix
int I[4][4] = {
{1, 0, 0, 0},
{0, 1, 0, 0},
{0, 0, 1, 0},
{0, 0, 0, 1}
};
// Multiply A × I and verify you get A back