Passing a multidimensional variable length array to a function

Passing arrays to functions is a bit funny in C and C++. There are no rvalues of array types, so you’re actually passing a pointer.

To address a 2D array (a real one, not array of arrays), you’ll need to pass 2 chunks of data:

  • the pointer to where it starts
  • how wide one row is

And these are two separate values, be it C or C++ or with VLA or without or whatnot.

Some ways to write that:

Simplest, works everywhere but needs more manual work

void foo(int width, int* arr) {
    arr[x + y*width] = 5;
}

VLA, standard C99

void foo(int width, int arr[][width]) {
    arr[x][y] = 5;
}

VLA w/ reversed arguments, forward parameter declaration (GNU C extension)

void foo(int width; int arr[][width], int width) {
    arr[x][y]=5;
}

C++ w/ VLA (GNU C++ extension, terribly ugly)

void foo(int width, int* ptr) {
    typedef int arrtype[][width];
    arrtype& arr = *reinterpret_cast<arrtype*>(ptr);
    arr[x][y]=5;
}

Big remark:

The [x][y] notation with a 2D array works because the array’s type contains the width. No VLA = array types must be fixed at compile-time.

Hence: If you can’t use VLA, then…

  • there’s no way to handle it in C,
  • there’s no way to handle it without a proxy class w/ overloaded operator overloading in C++.

If you can use VLA (C99 or GNU C++ extensions), then…

  • you’re in the green in C,
  • you still need a mess in C++, use classes instead.

For C++, boost::multi_array is a solid choice.

A workaround

For 2D arrays, you can make two separate allocations:

  • a 1D array of pointers to T (A)
  • a 2D array of T (B)

Then set the pointers in (A) to point into respective rows of (B).

With this setup, you can just pass (A) around as a simple T** and it will behave well with [x][y] indexing.

This solution is nice for 2D, but needs more and more boilerplate for higher dimensions. It’s also slower than the VLA solution because of the extra layer of indirection.

You may also run into a similar solution with a separate allocation for every B‘s row. In C this looks like a malloc-in-a-loop, and is analogous of C++’s vector-of-vectors. However this takes away the benefit of having the whole array in one block.

Leave a Comment