Complete guide to 2D arrays in C including declaration, initialization, matrix operations, row-column access patterns, and practical examples with memory diagrams.
A two-dimensional array is essentially an array of arrays — it organizes data in a tabular format with rows and columns. If you think of a 1D array as a single row of boxes, a 2D array is a grid or matrix of boxes arranged in rows and columns.
2D arrays are everywhere in programming: storing matrices for mathematical operations, representing game boards, managing tabular data like spreadsheets, and handling image pixel data.
Declaration of 2D Arrays
The general syntax for declaring a two-dimensional array is:
data_type array_name[rows][columns];
Examples:
int matrix[3][4]; // 3 rows, 4 columns — 12 integers
float table[5][5]; // 5×5 table of floats
char grid[10][10]; // 10×10 character grid
Memory Layout: Row-Major Order
Although we think of 2D arrays as grids, memory is linear. C stores 2D arrays in row-major order — all elements of row 0 come first, then row 1, and so on.
int matrix[3][4] = {
{1, 2, 3, 4}, // Row 0
{5, 6, 7, 8}, // Row 1
{9, 10, 11, 12} // Row 2
};
Logical View (Grid):
Col 0 Col 1 Col 2 Col 3
Row 0 [ 1 | 2 | 3 | 4 ]
Row 1 [ 5 | 6 | 7 | 8 ]
Row 2 [ 9 | 10 | 11 | 12 ]
Physical Memory (Linear - Row Major):
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬────┬────┬────┐
│ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │ 12 │
└───┴───┴───┴───┴───┴───┴───┴───┴───┴────┴────┴────┘
[0][0] [0][1] [0][2] [0][3] [1][0] [1][1] ...
Address of matrix[i][j] = Base + (i × columns + j) × sizeof(int)
Initialization Methods
Method 1: Nested Braces (Recommended)
int matrix[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
Method 2: Flat Initialization
int matrix[3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
// Fills row by row: {1,2,3}, {4,5,6}, {7,8,9}
Method 3: Partial Initialization
int matrix[3][3] = {
{1, 2}, // Row 0: {1, 2, 0}
{4}, // Row 1: {4, 0, 0}
{7, 8, 9} // Row 2: {7, 8, 9}
};
Method 4: Omitting Row Size
You can omit the first dimension (rows) when initializing, but the second dimension (columns) is always required:
int matrix[][3] = {
{1, 2, 3},
{4, 5, 6}
};
// Compiler infers 2 rows
Accessing and Modifying Elements
#include <stdio.h>
int main() {
int matrix[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// Access specific element
printf("Element at [1][2] = %d\n", matrix[1][2]); // 6
// Modify element
matrix[0][0] = 100;
printf("Modified [0][0] = %d\n", matrix[0][0]); // 100
return 0;
}
Element at [1][2] = 6
Modified [0][0] = 100
Reading and Displaying a 2D Array
#include <stdio.h>
int main() {
int rows = 3, cols = 3;
int matrix[3][3];
// Input
printf("Enter elements of 3x3 matrix:\n");
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
printf(" [%d][%d]: ", i, j);
scanf("%d", &matrix[i][j]);
}
}
// Display
printf("\nMatrix:\n");
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
printf("%4d", matrix[i][j]);
}
printf("\n");
}
return 0;
}
Enter elements of 3x3 matrix:
[0][0]: 1
[0][1]: 2
[0][2]: 3
[1][0]: 4
[1][1]: 5
[1][2]: 6
[2][0]: 7
[2][1]: 8
[2][2]: 9
Matrix:
1 2 3
4 5 6
7 8 9
Matrix Operations
Matrix Addition
#include <stdio.h>
int main() {
int a[2][3] = {{1, 2, 3}, {4, 5, 6}};
int b[2][3] = {{7, 8, 9}, {10, 11, 12}};
int result[2][3];
// Addition
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
result[i][j] = a[i][j] + b[i][j];
}
}
// Display result
printf("Sum of matrices:\n");
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
printf("%4d", result[i][j]);
}
printf("\n");
}
return 0;
}
Sum of matrices:
8 10 12
14 16 18
Matrix Multiplication
#include <stdio.h>
int main() {
int a[2][3] = {{1, 2, 3}, {4, 5, 6}};
int b[3][2] = {{7, 8}, {9, 10}, {11, 12}};
int result[2][2] = {0};
// Multiply: (2×3) × (3×2) = (2×2)
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
for (int k = 0; k < 3; k++) {
result[i][j] += a[i][k] * b[k][j];
}
}
}
printf("Product:\n");
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
printf("%5d", result[i][j]);
}
printf("\n");
}
return 0;
}
Matrix Transpose
#include <stdio.h>
int main() {
int matrix[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
int transpose[3][3];
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
transpose[j][i] = matrix[i][j];
}
}
printf("Original:\n");
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++)
printf("%3d", matrix[i][j]);
printf("\n");
}
printf("\nTranspose:\n");
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++)
printf("%3d", transpose[i][j]);
printf("\n");
}
return 0;
}
Original:
1 2 3
4 5 6
7 8 9
Transpose:
1 4 7
2 5 8
3 6 9
Row-wise and Column-wise Operations
#include <stdio.h>
int main() {
int matrix[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
// Row-wise sum
printf("Row sums: ");
for (int i = 0; i < 3; i++) {
int sum = 0;
for (int j = 0; j < 4; j++)
sum += matrix[i][j];
printf("%d ", sum);
}
// Column-wise sum
printf("\nCol sums: ");
for (int j = 0; j < 4; j++) {
int sum = 0;
for (int i = 0; i < 3; i++)
sum += matrix[i][j];
printf("%d ", sum);
}
printf("\n");
return 0;
}
Row sums: 10 26 42
Col sums: 15 18 21 24
Diagonal Elements
For square matrices, accessing diagonal elements is a common operation:
#include <stdio.h>
int main() {
int matrix[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
int n = 3;
printf("Primary diagonal: ");
for (int i = 0; i < n; i++)
printf("%d ", matrix[i][i]);
printf("\nSecondary diagonal: ");
for (int i = 0; i < n; i++)
printf("%d ", matrix[i][n - 1 - i]);
printf("\n");
return 0;
}
Primary diagonal: 1 5 9
Secondary diagonal: 3 5 7
Interview Questions
Q1: Why must the column size be specified when declaring a 2D array in C?
The compiler needs the column count to calculate memory addresses. The address formula base + (i × cols + j) × sizeof(type) requires knowing cols. Without it, the compiler cannot determine where each row begins.
Q2: What's the difference between row-major and column-major order?
In row-major order (used by C), elements of each row are stored contiguously. In column-major order (used by Fortran), elements of each column are stored contiguously. This affects cache performance when traversing matrices.
Q3: How do you pass a 2D array to a function in C?
You must specify at least the column size: void func(int arr[][4], int rows). Alternatively, use a pointer: void func(int (*arr)[4], int rows). The row count is typically passed as a separate parameter.
Q4: Can you have a 2D array with different row lengths (jagged array) in C?
Not with static 2D arrays. However, you can simulate jagged arrays using an array of pointers, where each pointer points to a dynamically allocated row of different length.
Summary
- 2D arrays store data in a matrix format with rows and columns
- C uses row-major order for memory storage
- Column size must always be specified in declarations
- Address formula:
base + (i × cols + j) × sizeof(type) - Common operations: addition, multiplication, transpose, diagonal access
- Nested loops are the standard pattern for traversing 2D arrays