Solarian Programmer

My programming ramblings

C Programming - Passing a multi-dimensional array to a function

Posted on March 27, 2019 by Paul

In this article I will show you how to pass a multi-dimensional array as a parameter to a function in C. For simplicity, we will present only the case of 2D arrays, but same considerations will apply to a general, multi-dimensional, array.

There is also a video version of this tutorial:

In C, a two-dimensional array is a one-dimensional array of one-dimensional arrays. For example, an array of two rows and 3 columns is technically a one-dimensional array of two elements, where each element is a one-dimensional 3 elements array. Here is an example of a 2D array of two rows and three columns:

1 int arr[][3] = {
2     {1, 2, 3},
3     {4, 5, 6}	
4 };

Please note, that in C, you need to explicitly define the second, third, fourth and so on dimensions of an array. For example, if you want to create a three-dimensional array:

1 int a[][3][2];

The simplest approach to pass a two-dimensional array to a function is to specify the second dimension of the array, e.g.:

 1 #include <stdio.h>
 2 
 3 void print_2d_array(int rows, int cols, int a[][3]) {
 4     for(int i = 0; i < rows; ++i) {
 5         for(int j = 0; j < cols; ++j) {
 6             printf("%d ", a[i][j]);
 7         }
 8         printf("\n");
 9     }
10 }
11 
12 int main(void) {
13     int arr[][3] = {
14         {1, 2, 3},
15         {4, 5, 6}	
16     };
17 
18     print_2d_array(2, 3, arr);
19 }

The problem with the above approach is that you will only be able to pass 2D arrays with three columns to the print_2d_array function.

Please note, that you can write the print_2D_array with the alternative syntax:

1 #include <stdio.h>
2 
3 void print_2d_array(int rows, int cols, int (*a)[3]) {
4     // ... print the array
5 }
6 
7 // ...

which says that a is a pointer to an array of 3 integers.

A more flexible approach, is to pass the array as a pointer to the block of memory that stores the arr variable, e.g.:

 1 #include <stdio.h>
 2 
 3 void print_2d_array(int rows, int cols, int *a) {
 4     for(int i = 0; i < rows; ++i) {
 5         for(int j = 0; j < cols; ++j) {
 6             printf("%d ", a[i * cols + j]);
 7         }
 8         printf("\n");
 9     }
10 }
11 
12 int main(void) {
13     int arr[][3] = {
14         {1, 2, 3},
15         {4, 5, 6}	
16     };
17 
18     print_2d_array(2, 3, arr[0]);
19 }

The advantage of this approach is that you can pass any 2D array shape to the print_2d_array function, not only 2x3 arrays like for the first version. Another advantage is that you can use the same function to print a dynamically allocated array. A slight disadvantage is that we lose the array shape information, inside the print_2d_array function, and we can’t access the array elements using:

1     a[i][j]

but the more cumbersome syntax:

1     a[i * cols + j]

Here is an example of passing a dynamically allocated array to a function:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 void print_2d_array(int rows, int cols, int *a) {
 5     for(int i = 0; i < rows; ++i) {
 6         for(int j = 0; j < cols; ++j) {
 7             printf("%d ", a[i * cols + j]);
 8         }
 9         printf("\n");
10     }
11 }
12 
13 int main(void) {
14     int rows = 0, cols = 0;
15     printf("Give me the array rows x cols dimensions:\n");
16     printf("rows = ");
17     scanf("%d", &rows);
18     //  ... for production code check scanf error code !!!
19     printf("cols = ");
20     scanf("%d", &cols);
21     //  ... for production code check scanf error code !!!
22     
23     int *arr = malloc(rows * cols * sizeof(int));
24     //  ... for production code check if the array was successfully allocated
25 
26     // Initialize the array
27     for(int i = 0; i < rows * cols; ++i) {
28         arr[i] = i;
29     }
30 
31     print_2d_array(rows, cols, arr);
32 
33     free(arr);
34 }

If your compiler supports C99’s flexible array members you can conveniently group the array and dimensions information in a struct, e.g.:

1 typedef struct {
2     int rows;
3     int cols;
4     int data[];
5 } Matrix2D;

The size of the Matrix2D structure is twice the size of an integer, the size of the data array, the so called flexible array member, is zero. Please note that the flexible array member should be the last element in the structure. Another observation is that flexible array members are not allowed in ISO C++, although some C++ compilers have support for this as an extension.

Here is an example of using the above structure:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 typedef struct {
 5     int rows;
 6     int cols;
 7     int data[];
 8 } Matrix2D;
 9 
10 void print_fma(Matrix2D *m) {
11     for(int i = 0; i < m->rows; ++i) {
12         for(int j = 0; j < m->cols; ++j) {
13             printf("%d ", m->data[i * m->cols + j]);
14         }
15         printf("\n");
16     }
17 }
18 
19 int main(void) {
20     int rows = 0, cols = 0;
21     printf("Give me the array rows x cols dimensions:\n");
22     printf("rows = ");
23     scanf("%d", &rows);
24     //  ... for production code check scanf error code !!!
25     printf("cols = ");
26     scanf("%d", &cols);
27     //  ... for production code check scanf error code !!!
28 
29     // Allocate memory for the Matrix2D struct + the array
30     Matrix2D *arr = malloc(sizeof(Matrix2D) + rows * cols * sizeof(int));
31     arr->rows = rows;
32     arr->cols = cols;
33 
34     // Initialize the array
35     for(int i = 0; i < rows * cols; ++i) {
36         arr->data[i] = i;
37     }
38 
39     print_fma(arr);
40 
41     // free the Matrix2D
42     free(arr);
43 }

If your C compiler has support for variable length arrays, you can pass the second dimension of the array as a variable to the function. Please note that, at the time of this writing, Visual Studio 2019 doesn’t have support for variable length arrays. So you won’t be able to use the next two examples with the Visual Studio 2019 C compiler. Another observation is that variable length arrays are not allowed in ISO C++.

 1 #include <stdio.h>
 2 
 3 void print_2d_array(int rows, int cols, int a[][cols]) {
 4     for(int i = 0; i < rows; ++i) {
 5         for(int j = 0; j < cols; ++j) {
 6             printf("%d ", a[i][j]);
 7         }
 8         printf("\n");
 9     }
10 }
11 
12 int main(void) {
13     int arr[][3] = {
14         {1, 2, 3},
15         {4, 5, 6}	
16     };
17 
18     print_2d_array(2, 3, arr);
19 }

Or, if you need to initialize the array at runtime:

 1 #include <stdio.h>
 2 
 3 void print_2d_array(int rows, int cols, int a[][cols]) {
 4     for(int i = 0; i < rows; ++i) {
 5         for(int j = 0; j < cols; ++j) {
 6             printf("%d ", a[i][j]);
 7         }
 8         printf("\n");
 9     }
10 }
11 
12 int main(void) {
13     int rows = 0, cols = 0;
14     printf("Give me the array rows x cols dimensions:\n");
15     printf("rows = ");
16     scanf("%d", &rows);
17     //  ... for production code check scanf error code !!!
18     printf("cols = ");
19     scanf("%d", &cols);
20     //  ... for production code check scanf error code !!!
21     
22     // needs VLA support
23     int arr[rows][cols];
24 
25     // Initialize the array
26     for(int i = 0, kk = 0; i < rows; ++i) {
27         for(int j = 0; j < cols; ++j) {
28             arr[i][j] = kk;
29             kk++;
30         }
31     }
32 
33     print_2d_array(rows, cols, arr);
34 }

Another interesting case is the so-called dynamically allocated two-dimensional array, technically this is a dynamically allocated array of pointers to dynamically allocated arrays. Here is an example of passing a 2D dynamically allocated array to a function:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 void print_2d_array_of_pointers(int rows, int cols, int **a) {
 5     for(int i = 0; i < rows; ++i) {
 6         for(int j = 0; j < cols; ++j) {
 7             printf("%d ", a[i][j]);
 8         }
 9         printf("\n");
10     }
11 }
12 
13 // ...

In order to allocate memory for the above array we need to first allocate memory for the row pointers and next allocate memory for each row in a loop. Here is a possible implementation:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 void print_2d_array_of_pointers(int rows, int cols, int **a) {
 5     // ... print the array
 6 }
 7 
 8 int main(void) {
 9     int rows = 0, cols = 0;
10     printf("Give me the array rows x cols dimensions:\n");
11     printf("rows = ");
12     scanf("%d", &rows);
13     //  ... for production code check scanf error code !!!
14     printf("cols = ");
15     scanf("%d", &cols);
16     //  ... for production code check scanf error code !!!
17 
18     // allocate memory for the rows x cols array
19     int **arr = malloc(rows * sizeof(int*));
20     //  ... for production code check if the array was successfully allocated
21     for(int i = 0; i < rows; ++i) {
22         arr[i] = malloc(cols * sizeof(int));
23         //  ... for production code check if the array was successfully allocated
24     }
25 
26     // Initialize the array
27     for(int i = 0, kk = 0; i < rows; ++i) {
28         for(int j = 0; j < cols; ++j) {
29             arr[i][j] = kk;
30             kk++;
31         }
32     }
33 
34     print_2d_array_of_pointers(rows, cols, arr);
35 
36     // free the memory
37     for(int i = 0; i < rows; ++i) {
38         free(arr[i]);
39     }
40     free(arr);
41 }

If you want to learn more about C99/C11 I would recommend reading 21st Century C: C Tips from the New School by Ben Klemens:

or the classic C Bible, The C Programming Language by B.W. Kernighan, D.M. Ritchie:


Show Comments