How to pass by reference multidimensional array with unknown size in C or C++?
For example, in main function I have:
int main(){
int
H2CO3's solution will work for C99 or a C2011 compiler that supports VLAs. For C89 or a C2011 compiler that doesn't support VLAs, or (God forbid) a K&R C compiler, you'd have to do something else.
Assuming you're passing a contiguously allocated array, you can pass a pointer to the first element (&a[0][0]
) along with the dimension sizes, and then treat it as a 1-D array, mapping indices like so:
void foo( int *a, size_t rows, size_t cols )
{
size_t i, j;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
a[i * rows + j] = some_value();
}
}
}
int main( void )
{
int arr[10][20];
foo( &arr[0][0], 10, 20 );
...
return 0;
}
This will work for arrays allocated on the stack:
T a[M][N];
and for dynamically allocated arrays of the form:
T (*ap)[N] = malloc( M * sizeof *ap );
since both will have contiguously allocated rows. This will not work (or at least, not be guaranteed to work) for dynamically allocated arrays of the form:
T **ap = malloc( M * sizeof *ap );
if (ap)
{
size_t i;
for (i = 0; i < M; i++)
{
ap[i] = malloc( N * sizeof *ap[i] );
}
}
since it's not guaranteed that all the rows will be allocated contiguously to each other.
This is a sort of comment to the good answer of @John Bode
This will not work (or at least, not be guaranteed to work) for dynamically allocated arrays of the form:
But this variant will:
T **ap = malloc( M * sizeof *ap );
if (ap) return NULL; ---> some error atention
if (ap)
{
ap[0] = malloc( M * N * sizeof *ap[i] );
if (ap[0]) { free(ap); return NULL;} ---> some error atention
size_t i;
for (i = 1; i < M; i++)
{
ap[i] = ap[0] + i * N;
}
}
After use :
free(ap[0]);
free(ap);
for T
being int
you call foo
exactly als for the array int ap[M][N];
foo( &ap[0][0], M, N);
since you guaranteed that all the rows are allocated contiguously to each other. This allocation is a litter more efficient.
Simply put, you can't. In C, you can't pass by reference, since C has no references. In C++, you can't pass arrays with unknown size, since C++ doesn't support variable-lenght arrays.
Alternative solutions: in C99, pass a pointer to the variable-length array; in C++, pass a reference to std::vector<std::vector<T>>
.
Demonstration for C99:
#include <stdio.h>
void foo(int n, int k, int (*arr)[n][k])
{
int i, j;
for (i = 0; i < n; i++) {
for (j = 0; j < k; j++) {
printf("%3d ", (*arr)[i][j]);
}
printf("\n");
}
}
int main(int argc, char *argv[])
{
int a = strtol(argv[1], NULL, 10);
int b = strtol(argv[2], NULL, 10);
int arr[a][b];
int i, j;
for (i = 0; i < a; i++) {
for (j = 0; j < b; j++) {
arr[i][j] = i * j;
}
}
foo(a, b, &arr);
return 0;
}
Demonstration for C++03:
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
void foo(std::vector < std::vector < int > > &vec)
{
for (std::vector < std::vector < int > >::iterator i = vec.begin(); i != vec.end(); i++) {
for (std::vector<int>::iterator j = i->begin(); j != i->end(); j++) {
std::cout << *j << " ";
}
std::cout << std::endl;
}
}
int main(int argc, char *argv[])
{
int i = strtol(argv[1], NULL, 10);
int j = strtol(argv[2], NULL, 10);
srand(time(NULL));
std::vector < std::vector < int > > vec;
vec.resize(i);
for (std::vector < std::vector < int > >::iterator it = vec.begin(); it != vec.end(); it++) {
it->resize(j);
for (std::vector<int>::iterator jt = it->begin(); jt != it->end(); jt++) {
*jt = random() % 10;
}
}
foo(vec);
return 0;
}
John Bode's explanation is very good, but there is a little mistake: it should be
i * cols + j
instead of
i * rows + j
If you really want references, then it's only in C++.
En example of a two-dimensional int array passed by reference
void function_taking_an_array(int**& multi_dim_array);
But the reference doesn't have any advantage, so simply use :
void function_taking_an_array(int** multi_dim_array);
I would advice you to use a container to hold your array.