Module 6 · Lesson 1

Memory Layout: Strides & Order

.strides tells you how many bytes to step to move one position along each axis. For a C-order (row-major, the default) (2, 3) array of float64, moving one column over costs 8 bytes, but moving one row down costs 3 * 8 = 24 bytes — because rows are stored one after another in memory.

Fortran order (order="F") stores columns contiguously instead — the strides flip. This is why .T (transpose) is instant and never copies data: it just swaps the strides and shape, leaving the underlying buffer alone. That also means a transposed array is usually not C-contiguous anymore. When an algorithm (or a library written in C) genuinely needs a contiguous buffer, use np.ascontiguousarray(arr) — it returns arr itself if it’s already contiguous, and a real copy only if it isn’t.

a = np.arange(6, dtype=np.float64).reshape(2, 3)
print("C-order strides:", a.strides)       # (24, 8): 24 bytes per row, 8 per column
print("is C-contiguous:", a.flags["C_CONTIGUOUS"])

at = a.T
print("\ntransposed strides:", at.strides)   # strides just swapped, no copy
print("transpose is C-contiguous:", at.flags["C_CONTIGUOUS"])
print("transpose shares memory with a:", np.shares_memory(a, at))

f = np.asfortranarray(a)
print("\nFortran-order strides:", f.strides)

Output:

C-order strides: (24, 8)
is C-contiguous: True

transposed strides: (8, 24)
transpose is C-contiguous: False
transpose shares memory with a: True

Fortran-order strides: (8, 16)
1.1

Spot the view

Write second_row_view(matrix) that returns a view (not a copy) of row index 1 of a 2-D array, using basic slicing.

💡 Hint

Plain slicing with matrix[1] (or matrix[1, :]) already returns a view — no .copy() needed.

✅ Solution
def second_row_view(matrix):
    return matrix[1]
1.2

Force a contiguous copy

Write ensure_contiguous(arr) that returns a C-contiguous version of arr. If arr is already C-contiguous, return it unchanged (same underlying buffer); otherwise return a new, C-contiguous array with the same shape and values.

💡 Hint

np.ascontiguousarray does exactly this: no-op copy if already contiguous, real copy otherwise.

✅ Solution
def ensure_contiguous(arr):
    return np.ascontiguousarray(arr)