How to Pass a Multidimensional Array to a Function in C and C++

How to pass 2D array (matrix) in a function in C?

C does not really have multi-dimensional arrays, but there are several ways to simulate them. The way to pass such arrays to a function depends on the way used to simulate the multiple dimensions:

1) Use an array of arrays. This can only be used if your array bounds are fully determined at compile time, or if your compiler supports VLA's:

#define ROWS 4
#define COLS 5

void func(int array[ROWS][COLS])
{
int i, j;

for (i=0; i<ROWS; i++)
{
for (j=0; j<COLS; j++)
{
array[i][j] = i*j;
}
}
}

void func_vla(int rows, int cols, int array[rows][cols])
{
int i, j;

for (i=0; i<rows; i++)
{
for (j=0; j<cols; j++)
{
array[i][j] = i*j;
}
}
}

int main()
{
int x[ROWS][COLS];

func(x);
func_vla(ROWS, COLS, x);
}

2) Use a (dynamically allocated) array of pointers to (dynamically allocated) arrays. This is used mostly when the array bounds are not known until runtime.

void func(int** array, int rows, int cols)
{
int i, j;

for (i=0; i<rows; i++)
{
for (j=0; j<cols; j++)
{
array[i][j] = i*j;
}
}
}

int main()
{
int rows, cols, i;
int **x;

/* obtain values for rows & cols */

/* allocate the array */
x = malloc(rows * sizeof *x);
for (i=0; i<rows; i++)
{
x[i] = malloc(cols * sizeof *x[i]);
}

/* use the array */
func(x, rows, cols);

/* deallocate the array */
for (i=0; i<rows; i++)
{
free(x[i]);
}
free(x);
}

3) Use a 1-dimensional array and fixup the indices. This can be used with both statically allocated (fixed-size) and dynamically allocated arrays:

void func(int* array, int rows, int cols)
{
int i, j;

for (i=0; i<rows; i++)
{
for (j=0; j<cols; j++)
{
array[i*cols+j]=i*j;
}
}
}

int main()
{
int rows, cols;
int *x;

/* obtain values for rows & cols */

/* allocate the array */
x = malloc(rows * cols * sizeof *x);

/* use the array */
func(x, rows, cols);

/* deallocate the array */
free(x);
}

4) Use a dynamically allocated VLA. One advantage of this over option 2 is that there is a single memory allocation; another is that less memory is needed because the array of pointers is not required.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

extern void func_vla(int rows, int cols, int array[rows][cols]);
extern void get_rows_cols(int *rows, int *cols);
extern void dump_array(const char *tag, int rows, int cols, int array[rows][cols]);

void func_vla(int rows, int cols, int array[rows][cols])
{
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
array[i][j] = (i + 1) * (j + 1);
}
}
}

int main(void)
{
int rows, cols;

get_rows_cols(&rows, &cols);

int (*array)[cols] = malloc(rows * cols * sizeof(array[0][0]));
/* error check omitted */

func_vla(rows, cols, array);
dump_array("After initialization", rows, cols, array);

free(array);
return 0;
}

void dump_array(const char *tag, int rows, int cols, int array[rows][cols])
{
printf("%s (%dx%d):\n", tag, rows, cols);
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
printf("%4d", array[i][j]);
putchar('\n');
}
}

void get_rows_cols(int *rows, int *cols)
{
srand(time(0)); // Only acceptable because it is called once
*rows = 5 + rand() % 10;
*cols = 3 + rand() % 12;
}

(See srand() — why call it only once?.)

How to pass a multidimensional C array to a function?

However, my professor said that the number of stars in the definition depends on the number of dimensions in the array. So, an int[] would become an int*, a int[][] would become an int**, etc.

I'm really, really hoping you simply misunderstood what he was saying, because that's not correct.

Except when it is the operand of the sizeof or unary & operators, or is a string literal used to initialize a character array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array. If T is an array type, you wind up with a pointer to an array, not a pointer to a pointer.

Going through some examples:

int arr[10];
...
foo( arr, 10 ); // need to pass number of rows as a separate parameter

In the call to foo, the expression arr has type "10-element array of int". Since it's not the operand of the sizeof or unary & operators, it "decays" to type int *, and the value of the expression will be the address of the first element. Thus, the prototype for foo would be

void foo( int *arr, size_t rows ); // or int arr[]; it means the same thing in this context

Notice that this is the same type as the result of the expression &arr[0]. arr[0] is an int object, so &arr[0] gives us an int *. IOW, arr == &arr[0].

So far so good. Now let's look at a 2D array:

int arr[10][20];
...
foo( arr, 10 );

In this case, the expression arr has type "10-element array of 20-element array of int"; it "decays" to an expression of type "pointer to 20-element array of int"; thus, the prototype for foo becomes

void foo( int (*arr)[20], size_t rows ); // or int arr[][20]

Remember the part above where it says "except when it is the operand of ... the unary & operator"? If we write &arr[0], arr[0] has type "20-element array of int", but it does not automatically decay to a pointer. So instead of getting an expression of type int **, we get an expression of type int (*)[20]. So again, arr == &arr[0].

Now let's look at a 3D array:

int arr[10][20][30];
...
foo( arr, 10 );

This time, the expression arr has type "10-element array of 20-element array of 30-element array of int". This time, it "decays" to an expression of type "pointer to 20-element array of 30-element array of int", and the prototype is now

void foo( int (*arr)[20][30], size_t rows ); // or int arr[][20][30]

And once again, arr[0] has an array type, so the expression &arr[0] gives us the type int (*)[20][30]; again, arr == &arr[0].

The pattern for higher-dimensioned arrays should be clear from here on out.

Now, this brings up a minor issue. A pointer to an N-element array is a different type from pointer to an M-element array, where N != M. If your function prototype is

void foo( int (*)[20], size_t rows );

then it will only work with Nx20 arrays; you cannot pass it a pointer to an array with a different outer dimension:

void foo( int (*ap)[20], size_t rows );
...
int arr1[10][20];
int arr2[20][20];
int arr3[20][30];

foo( arr1, 10 ); // okay
foo( arr2, 20 ); // okay
foo( arr3, 20 ); // not okay - arr3 has type int (*)[30], which is not *compatible*
// with int (*)[20]

EDIT

In the case where a function is expecting an int * and you have a multi-dimensional array, you'd explicitly pass a pointer to the first element:

void foo( int *, size_t size );
...
int arr2[10][20];
int arr3[20][10][5];

foo( &arr2[0][0], sizeof arr2 / sizeof arr2[0][0] );
foo( &arr3[0][0][0], sizeof arr3 / sizeof arr3[0][0][0] );

Passing multidimensional arrays as arguments in functions in C

The function func() expects a pointer to int but you are passing a pointer to an array. Hence, the errrors.
It's because an array gets converted into a pointer to its first element when you pass it to a function.

You can change the function prototype and definition to receive a pointer to an array:

void func(int (*array)[3], int size);

int main()
{
int size = 3;
int array[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
func(array,size);
printf("Done");
}

void func(int (*array)[3], int size) {
...
}

Note that your array is initialized with size 3x3. So the array size has to 3x3 at least.


C99 allows to you pass dimensions. So you can write it like this too:

void func(int x, int y, int a[x][y]);

int main()
{
int size = 3;
int array[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
func(3, 3, array);
printf("Done");
}

void func(int x, int y, int array[x][y])
{
printf("%i %i %i\n", array[0][0],array[1][1], array[2][2]);
}

Passing 3D array as parameter to a function in C

  1. You can not omit the types
  2. You can omit only the first dimension of an array

int sum3darray(a[][][], size);

should be

int sum3darray(int a[][3][3], int size);

or

int sum3darray(int (*a)[3][3], int size);

As pointed out by @CoolGuy, you can omit the name of the parameters in prototypes:

int sum3darray(int (*a)[3][3], int size);

can be written as

int sum3darray(int (*)[3][3], int);

Another way to deal with multidimensional arrays (if you don't know the sizes beforehand) is using VLA's (thank you M Oehm) or flattening the array manually, take a look.

How to pass a multidimensional array to a function without inner dimension in c++?

You can pass an arbitrary 2d array by reference if you could change MyFunction to:

template<std::size_t N, std::size_t M>
void MyFunction(double (&myArray)[N][M]) {
// ...
}

This way you would also have dimensions of the array.

Passing a 2D array to a C++ function

There are three ways to pass a 2D array to a function:

  1. The parameter is a 2D array

    int array[10][10];
    void passFunc(int a[][10])
    {
    // ...
    }
    passFunc(array);
  2. The parameter is an array containing pointers

    int *array[10];
    for(int i = 0; i < 10; i++)
    array[i] = new int[10];
    void passFunc(int *a[10]) //Array containing pointers
    {
    // ...
    }
    passFunc(array);
  3. The parameter is a pointer to a pointer

    int **array;
    array = new int *[10];
    for(int i = 0; i <10; i++)
    array[i] = new int[10];
    void passFunc(int **a)
    {
    // ...
    }
    passFunc(array);


Related Topics



Leave a reply



Submit