Docs

Multi Dimensional Arrays

Multi-Dimensional Arrays in C

Table of Contents

  1. β€’Introduction
  2. β€’What are Multi-Dimensional Arrays?
  3. β€’Two-Dimensional Arrays
  4. β€’Declaration and Initialization
  5. β€’Accessing Elements
  6. β€’Memory Layout
  7. β€’Common Operations
  8. β€’Three-Dimensional Arrays
  9. β€’Passing to Functions
  10. β€’Common Mistakes
  11. β€’Best Practices
  12. β€’Summary

Introduction

Multi-dimensional arrays extend the concept of arrays to store data in a tabular or matrix format. They are essential for representing grids, tables, matrices, images, and other structured data.


What are Multi-Dimensional Arrays?

A multi-dimensional array is an array of arrays. The most common type is the two-dimensional array (2D array), which can be visualized as a table with rows and columns.

Types of Multi-Dimensional Arrays

DimensionDescriptionExample Use Case
1DLinear listSimple list of values
2DTable/MatrixSpreadsheet, game board
3DCube of data3D graphics, video frames
nDHigher dimensionsScientific simulations

Visual Comparison

1D Array (List):
β”Œβ”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”
β”‚ 1 β”‚ 2 β”‚ 3 β”‚ 4 β”‚ 5 β”‚
β””β”€β”€β”€β”΄β”€β”€β”€β”΄β”€β”€β”€β”΄β”€β”€β”€β”΄β”€β”€β”€β”˜

2D Array (Table/Matrix):
     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  β”‚
    β””β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”˜

3D Array (Cube):
         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        /β”‚  Layer 0       /β”‚
       / β”‚               / β”‚
      /  β”‚              /  β”‚
     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
     β”‚   Layer 1     β”‚    β”‚
     β”‚   β”Œβ”€β”¬β”€β”¬β”€β”     β”‚   /
     β”‚   β”œβ”€β”Όβ”€β”Όβ”€β”€     β”‚  /
     β”‚   β””β”€β”΄β”€β”΄β”€β”˜     β”‚ /
     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜/

Two-Dimensional Arrays

Concept

A 2D array is organized as rows and columns, similar to a spreadsheet or matrix.

int matrix[3][4];  // 3 rows, 4 columns

         Column
         0   1   2   3
       β”Œβ”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”
Row 0  β”‚   β”‚   β”‚   β”‚   β”‚
       β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”€
Row 1  β”‚   β”‚   β”‚   β”‚   β”‚
       β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”€
Row 2  β”‚   β”‚   β”‚   β”‚   β”‚
       β””β”€β”€β”€β”΄β”€β”€β”€β”΄β”€β”€β”€β”΄β”€β”€β”€β”˜

Total elements = Rows Γ— Columns = 3 Γ— 4 = 12

Syntax

data_type array_name[rows][columns];

Examples

int matrix[3][4];           // 3 rows, 4 columns of integers
float grades[5][3];         // 5 students, 3 subjects
char board[8][8];           // 8x8 chess board
double pixels[1080][1920];  // HD screen pixels

Declaration and Initialization

Method 1: Declaration Only

int matrix[3][4];  // Uninitialized (contains garbage)

Method 2: Initialize with Values

int matrix[3][4] = {
    {1, 2, 3, 4},       // Row 0
    {5, 6, 7, 8},       // Row 1
    {9, 10, 11, 12}     // Row 2
};

Method 3: Partial Initialization

int matrix[3][4] = {
    {1, 2},             // Row 0: {1, 2, 0, 0}
    {5},                // Row 1: {5, 0, 0, 0}
    {9, 10, 11}         // Row 2: {9, 10, 11, 0}
};
// Remaining elements are 0

Method 4: All Zeros

int matrix[3][4] = {0};  // All 12 elements are 0

Method 5: Linear Initialization

int matrix[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
// Fills row by row automatically

Method 6: Omit First Dimension

int matrix[][4] = {
    {1, 2, 3, 4},
    {5, 6, 7, 8},
    {9, 10, 11, 12}
};
// Compiler determines rows = 3
// Note: Second dimension (columns) MUST be specified!

Initialization Visualization

int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};

Memory Layout:
β”Œβ”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”
β”‚ 1 β”‚ 2 β”‚ 3 β”‚ 4 β”‚ 5 β”‚ 6 β”‚
β””β”€β”€β”€β”΄β”€β”€β”€β”΄β”€β”€β”€β”΄β”€β”€β”€β”΄β”€β”€β”€β”΄β”€β”€β”€β”˜
 ↑           ↑
 Row 0       Row 1

Logical View:
      Col 0  Col 1  Col 2
     β”Œβ”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”
Row 0β”‚  1   β”‚  2   β”‚  3   β”‚
     β”œβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€
Row 1β”‚  4   β”‚  5   β”‚  6   β”‚
     β””β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”˜

Accessing Elements

Syntax

array_name[row_index][column_index]

Reading Elements

int matrix[3][4] = {
    {1, 2, 3, 4},
    {5, 6, 7, 8},
    {9, 10, 11, 12}
};

int element = matrix[1][2];  // Row 1, Column 2 β†’ 7
int first = matrix[0][0];    // First element β†’ 1
int last = matrix[2][3];     // Last element β†’ 12

Writing Elements

matrix[0][0] = 100;  // Change first element
matrix[1][2] = 77;   // Change element at row 1, col 2
matrix[2][3] = 999;  // Change last element

Index Ranges

For int arr[ROWS][COLS]:
- Valid row indices: 0 to ROWS-1
- Valid column indices: 0 to COLS-1

Element positions:
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ arr[0][0]   β”‚ arr[0][1]     β”‚ ... arr[0][COLS-1] β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ arr[1][0]   β”‚ arr[1][1]     β”‚ ... arr[1][COLS-1] β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ ...         β”‚ ...           β”‚ ...           β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚arr[ROWS-1][0]β”‚arr[ROWS-1][1]β”‚...arr[ROWS-1][COLS-1]β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Memory Layout

Row-Major Order

In C, 2D arrays are stored in row-major order: all elements of row 0 first, then row 1, and so on.

int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};
Logical View:          Memory (Row-Major):

    [0][1][2]          Address:  100  104  108  112  116  120
   β”Œβ”€β”€β”¬β”€β”€β”¬β”€β”€β”          β”Œβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”
[0]β”‚1 β”‚2 β”‚3 β”‚          β”‚ 1  β”‚ 2  β”‚ 3  β”‚ 4  β”‚ 5  β”‚ 6  β”‚
   β”œβ”€β”€β”Όβ”€β”€β”Όβ”€β”€β”€   β†’      β””β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”˜
[1]β”‚4 β”‚5 β”‚6 β”‚           ↑─────Row 0─────↑↑─────Row 1─────↑
   β””β”€β”€β”΄β”€β”€β”΄β”€β”€β”˜

Address Calculation

Address of arr[i][j] = Base + (i Γ— COLS + j) Γ— sizeof(element)

For arr[1][2] with base = 100, COLS = 3, sizeof(int) = 4:
Address = 100 + (1 Γ— 3 + 2) Γ— 4
        = 100 + 5 Γ— 4
        = 100 + 20
        = 120

Size Calculation

int matrix[3][4];

// Total size in bytes
size_t totalBytes = sizeof(matrix);  // 3 Γ— 4 Γ— 4 = 48 bytes

// Size of one row
size_t rowSize = sizeof(matrix[0]);  // 4 Γ— 4 = 16 bytes

// Number of rows
size_t rows = sizeof(matrix) / sizeof(matrix[0]);  // 3

// Number of columns
size_t cols = sizeof(matrix[0]) / sizeof(matrix[0][0]);  // 4

Common Operations

1. Traversing (Printing) a 2D Array

int matrix[3][4] = {
    {1, 2, 3, 4},
    {5, 6, 7, 8},
    {9, 10, 11, 12}
};

// Row by row traversal
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 4; j++) {
        printf("%3d ", matrix[i][j]);
    }
    printf("\n");
}

2. Sum of All Elements

int sum = 0;
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 4; j++) {
        sum += matrix[i][j];
    }
}
printf("Sum: %d\n", sum);

3. Row Sum and Column Sum

// Sum of each row
for (int i = 0; i < 3; i++) {
    int rowSum = 0;
    for (int j = 0; j < 4; j++) {
        rowSum += matrix[i][j];
    }
    printf("Row %d sum: %d\n", i, rowSum);
}

// Sum of each column
for (int j = 0; j < 4; j++) {
    int colSum = 0;
    for (int i = 0; i < 3; i++) {
        colSum += matrix[i][j];
    }
    printf("Column %d sum: %d\n", j, colSum);
}

4. Finding Maximum Element

int max = matrix[0][0];
int maxRow = 0, maxCol = 0;

for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 4; j++) {
        if (matrix[i][j] > max) {
            max = matrix[i][j];
            maxRow = i;
            maxCol = j;
        }
    }
}
printf("Max: %d at [%d][%d]\n", max, maxRow, maxCol);

5. Matrix Transpose

int original[2][3] = {{1, 2, 3}, {4, 5, 6}};
int transposed[3][2];

for (int i = 0; i < 2; i++) {
    for (int j = 0; j < 3; j++) {
        transposed[j][i] = original[i][j];
    }
}
Original [2][3]:     Transposed [3][2]:
β”Œβ”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”        β”Œβ”€β”€β”€β”¬β”€β”€β”€β”
β”‚ 1 β”‚ 2 β”‚ 3 β”‚        β”‚ 1 β”‚ 4 β”‚
β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”€   β†’    β”œβ”€β”€β”€β”Όβ”€β”€β”€β”€
β”‚ 4 β”‚ 5 β”‚ 6 β”‚        β”‚ 2 β”‚ 5 β”‚
β””β”€β”€β”€β”΄β”€β”€β”€β”΄β”€β”€β”€β”˜        β”œβ”€β”€β”€β”Όβ”€β”€β”€β”€
                     β”‚ 3 β”‚ 6 β”‚
                     β””β”€β”€β”€β”΄β”€β”€β”€β”˜

6. Matrix Addition

int A[2][2] = {{1, 2}, {3, 4}};
int B[2][2] = {{5, 6}, {7, 8}};
int C[2][2];  // Result

for (int i = 0; i < 2; i++) {
    for (int j = 0; j < 2; j++) {
        C[i][j] = A[i][j] + B[i][j];
    }
}
// C = {{6, 8}, {10, 12}}

7. Matrix Multiplication

int A[2][3] = {{1, 2, 3}, {4, 5, 6}};
int B[3][2] = {{7, 8}, {9, 10}, {11, 12}};
int C[2][2] = {0};  // Result: [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++) {
            C[i][j] += A[i][k] * B[k][j];
        }
    }
}

Three-Dimensional Arrays

Concept

A 3D array can be visualized as multiple 2D arrays stacked together (like layers or pages).

int cube[2][3][4];  // 2 layers, each with 3 rows and 4 columns
Layer 0 (cube[0]):         Layer 1 (cube[1]):
     [0][1][2][3]              [0][1][2][3]
    β”Œβ”€β”€β”¬β”€β”€β”¬β”€β”€β”¬β”€β”€β”             β”Œβ”€β”€β”¬β”€β”€β”¬β”€β”€β”¬β”€β”€β”
[0] β”‚  β”‚  β”‚  β”‚  β”‚         [0] β”‚  β”‚  β”‚  β”‚  β”‚
    β”œβ”€β”€β”Όβ”€β”€β”Όβ”€β”€β”Όβ”€β”€β”€             β”œβ”€β”€β”Όβ”€β”€β”Όβ”€β”€β”Όβ”€β”€β”€
[1] β”‚  β”‚  β”‚  β”‚  β”‚         [1] β”‚  β”‚  β”‚  β”‚  β”‚
    β”œβ”€β”€β”Όβ”€β”€β”Όβ”€β”€β”Όβ”€β”€β”€             β”œβ”€β”€β”Όβ”€β”€β”Όβ”€β”€β”Όβ”€β”€β”€
[2] β”‚  β”‚  β”‚  β”‚  β”‚         [2] β”‚  β”‚  β”‚  β”‚  β”‚
    β””β”€β”€β”΄β”€β”€β”΄β”€β”€β”΄β”€β”€β”˜             β””β”€β”€β”΄β”€β”€β”΄β”€β”€β”΄β”€β”€β”˜

Total elements = 2 Γ— 3 Γ— 4 = 24

Declaration and Initialization

int cube[2][3][4] = {
    // Layer 0
    {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12}
    },
    // Layer 1
    {
        {13, 14, 15, 16},
        {17, 18, 19, 20},
        {21, 22, 23, 24}
    }
};

Accessing Elements

int value = cube[1][2][3];  // Layer 1, Row 2, Column 3 β†’ 24
cube[0][0][0] = 100;        // First element
cube[1][2][3] = 999;        // Last element

Traversing 3D Array

for (int layer = 0; layer < 2; layer++) {
    printf("Layer %d:\n", layer);
    for (int row = 0; row < 3; row++) {
        for (int col = 0; col < 4; col++) {
            printf("%3d ", cube[layer][row][col]);
        }
        printf("\n");
    }
    printf("\n");
}

Passing to Functions

Important Rule

When passing multi-dimensional arrays to functions, all dimensions except the first must be specified.

Passing 2D Array

// Method 1: Specify all dimensions
void printMatrix(int arr[3][4], int rows) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < 4; j++) {
            printf("%d ", arr[i][j]);
        }
        printf("\n");
    }
}

// Method 2: Omit first dimension
void printMatrix(int arr[][4], int rows) {
    // Same as above
}

// Method 3: Pointer notation
void printMatrix(int (*arr)[4], int rows) {
    // Same as above
}

// Usage
int matrix[3][4] = {...};
printMatrix(matrix, 3);

Why Second Dimension is Required

The compiler needs to know the column size to calculate element addresses:

Address of arr[i][j] = Base + (i Γ— COLS + j) Γ— sizeof(element)
                              ↑
                       COLS must be known!

Variable Length Arrays (C99+)

void printMatrix(int rows, int cols, int arr[rows][cols]) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%d ", arr[i][j]);
        }
        printf("\n");
    }
}

Common Mistakes

1. Wrong Order of Indices

int matrix[3][4];  // 3 rows, 4 columns

// WRONG: Thinking [column][row]
matrix[4][3] = 10;  // Undefined behavior!

// CORRECT: [row][column]
matrix[2][3] = 10;

2. Missing Inner Braces

// Can work but confusing
int arr[2][3] = {1, 2, 3, 4, 5, 6};

// BETTER: Use inner braces
int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};

3. Omitting Required Dimension

// WRONG: Second dimension missing
void func(int arr[][]) {...}  // Error!

// CORRECT: Specify second dimension
void func(int arr[][4]) {...}

4. Out of Bounds Access

int matrix[3][4];

// WRONG: Accessing beyond limits
matrix[3][0] = 10;  // Row 3 doesn't exist!
matrix[0][4] = 10;  // Column 4 doesn't exist!

5. Confusing Size Calculations

void func(int arr[][4]) {
    // WRONG: sizeof(arr) gives pointer size, not array size
    int size = sizeof(arr);  // Size of pointer!
}

Best Practices

1. Use Named Constants for Dimensions

#define ROWS 3
#define COLS 4

int matrix[ROWS][COLS];

for (int i = 0; i < ROWS; i++) {
    for (int j = 0; j < COLS; j++) {
        // ...
    }
}

2. Initialize Arrays

int matrix[3][4] = {0};  // All zeros

3. Pass Dimensions to Functions

void processMatrix(int arr[][COLS], int rows, int cols) {
    // Use rows and cols for bounds checking
}

4. Check Bounds Before Access

if (row >= 0 && row < ROWS && col >= 0 && col < COLS) {
    matrix[row][col] = value;
}

5. Use Meaningful Variable Names

// Instead of i and j
for (int row = 0; row < ROWS; row++) {
    for (int col = 0; col < COLS; col++) {
        matrix[row][col] = row * COLS + col;
    }
}

Summary

Quick Reference

ConceptSyntax/Example
Declarationint arr[3][4];
Initializationint arr[2][3] = {{1,2,3}, {4,5,6}};
Access elementarr[row][col]
Total elementsrows Γ— columns
MemoryRow-major order (row by row)
Pass to functionfunc(int arr[][COLS], int rows)

Key Points

βœ“ 2D arrays are arrays of arrays
βœ“ Stored in row-major order in memory
βœ“ First index = row, Second index = column
βœ“ Valid indices: [0 to rows-1][0 to cols-1]
βœ“ When passing to functions, specify all dimensions except first
βœ“ Use nested loops to traverse (outer = rows, inner = columns)

Dimension Summary

1D: arr[SIZE]           - Single index
2D: arr[ROWS][COLS]     - Two indices (row, col)
3D: arr[D1][D2][D3]     - Three indices (layer, row, col)

Next Steps

After mastering multi-dimensional arrays:

  1. β€’Learn about Passing Arrays to Functions
  2. β€’Study Arrays and Pointers relationship
  3. β€’Explore Dynamic 2D Arrays with malloc
  4. β€’Practice matrix operations

"Think of 2D arrays as a table: rows go across, columns go down."

Multi Dimensional Arrays - C Programming Tutorial | DeepML