Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing a multidimensional variable length array to a function

Tags:

arrays

c

c99

There are tons of similar questions, but still I could not find any answer relevant for the feature of variable length arrays in C99/C11.

How to pass multidimensional variable length array to a function in C99/C11?

For example:

void foo(int n, int arr[][]) // <-- error here, how to fix? { }  void bar(int n) {     int arr[n][n];     foo(n, arr); } 

Compiler (g++-4.7 -std=gnu++11) says:
error: declaration of ‘arr’ as multidimensional array must have bounds for all dimensions except the first

If I change it to int *arr[], compiler still complains:
error: cannot convert ‘int (*)[(((sizetype)(((ssizetype)n) + -1)) + 1)]’ to ‘int**’ for argument ‘2’ to ‘void foo(int, int**)’

Next question, how to pass it by value and how to pass it by reference? Apparently, usually you don't want the entire array to be copied when you pass it to a function.

With constant length arrays it's simple, since, as the "constant" implies, you should know the length when you declare the function:

void foo2(int n, int arr[][10]) // <-- ok { }  void bar2() {     int arr[10][10];     foo2(10, arr); } 

I know, passing arrays to functions like this is not a best practice, and I don't like it at all. It is probably better to do with flat pointers, or objects (like std:vector) or somehow else. But still, I'm a bit curios what is the answer here from a theoretical standpoint.

like image 783
alveko Avatar asked Jan 27 '13 15:01

alveko


People also ask

Can you pass multidimensional array to a function?

In this tutorial, we will learn how to pass a single-dimensional and multidimensional array as a function parameter in C++ with the help of examples. In C++, we can pass arrays as an argument to a function. And, also we can return arrays from a function.

How do you pass the size of an array to a function?

The first one would be called like func1(foo, foo + CAPACITY) : passing in a pointer to the start of the array, and a pointer to just beyond the last element. The second would be called like func2(foo, CAPACITY) : passing in a pointer to the start of the array and the array size.

Can you pass an entire array to a function?

To pass an entire array to a function, only the name of the array is passed as an argument. result = calculateSum(num); However, notice the use of [] in the function definition. This informs the compiler that you are passing a one-dimensional array to the function.

Which is the correct way to declare a multidimensional array in C?

The basic form of declaring a two-dimensional array of size x, y: Syntax: data_type array_name[x][y];

How do you pass a multidimensional array to a function?

Passing Multidimensional Array to a Function. Multidimensional array can be passed in similar way as one-dimensional array. Consider this example to pass two dimensional array to a function: C++ Program to display the elements of two dimensional array by passing it to a function.

Should I Pass array sizes to functions or not?

If you need a function for 2D array of fixed size, don't pass the sizes. If you need a function that works with 2D arrays of any size, use the proper array passing technique. Your variants strikes me as a weird mix of the two. I don't see the point of doing it that way.

How to pass an array to a function in C++?

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: And these are two separate values, be it C or C++ or with VLA or without or whatnot.

What is the size of the array in the function display ()?

The size of the array is 5. When we call a function by passing an array as the argument, only the name of the array is used. Here, the argument marks represent the memory address of the first element of array marks [5]. However, notice the parameter of the display () function.


2 Answers

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.

like image 181
Kos Avatar answered Oct 05 '22 04:10

Kos


There is no clear cut way for doing this but you can use a workaround to treat a 2 dimensional array as a one dimensional array and then reconvert it to a two dimensional array inside the function.

void foo2(int n, int *arr)  {     int *ptr; // use this as a marker to go to next block     int i;     int j;      for(i = 0; i < n; i++)     {         ptr = arr + i*n; // this is the starting for arr[i] ...         for (j = 0; j < n ;j++)         {             printf(" %d ", ptr[j]); // This is same as arr[i][j]         }     } }  void bar2() {     int arr[10][10];     foo2(10, (int *)arr); } 
like image 25
Pankaj Rai Avatar answered Oct 05 '22 02:10

Pankaj Rai