data-structures · intermediate · ~15 min

Flatten a 2D array to 1D (row-major)

Manual row-major addressing and the equivalence with linear iteration.

Challenge

Implement void flatten_row_major(const int *src, int rows, int cols, int *dst) that copies a rows x cols grid (given as a contiguous block in src, row by row) into the 1D buffer dst in row-major order.

This is essentially a buffer copy, but the exercise is to write the explicit double loop and convince yourself that row-major [i * cols + j] indexing matches.

Examples

src = [1,2,3, 4,5,6]    (2x3 grid)
flatten_row_major(src, 2, 3, dst)
dst -> [1, 2, 3, 4, 5, 6]

Edge cases

  • rows == 0 or cols == 0 — no work to do.
  • Single-element grid.

Real-world tie-in

Functions like cv::Mat::reshape, numpy.ravel(), and BLAS cblas_dgemm all expect contiguous row-major layouts.

Why this matters

Real C code rarely uses int ** for matrices because pointer indirection trashes the cache. Storing a 2D grid in a single contiguous block and indexing [i * cols + j] is the standard high-performance layout (used by NumPy, BLAS, image libraries, etc.).

Input format

src of size rows*cols, then rows, cols, then dst of the same size.

Output format

dst filled with the same values in the same order.

Constraints

Use the explicit i * cols + j indexing form (don't just memcpy).

Starter code

void flatten_row_major(const int *src, int rows, int cols, int *dst) { /* TODO */ }

Common mistakes

Mixing up i and j (column-major addressing). Off-by-one on the outer loop. Mismatched destination size.

Edge cases to handle

0 rows; 0 cols; 1x1; non-square (rows != cols).

Complexity

O(rows * cols).

Background lessons

Up next

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.