lord.garbage
lord.garbage

Reputation: 5970

Passing multidimensional array in c90 (pre VLA-style)

Given the rise of VLA since c99 it has become easier to pass a multidimensional array of unknown size to a function. But there is a decent amount of controversy around using VLAs. Some readily endorse it "It is often nicer to use dynamic memory, alloca() or VLAs."1 others scorne them. The question I was asking myself is what the standard way was in the c90 days to passing a multidimensional array to a function. Here is a little code:

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

int main(int argc, char *argv[])
{

        int arr[2][4];

        int i;
        int j;

        for(i = 0; i < 2; i++) {
                for(j = 0; j < 4; j++) {
                        arr[i][j] = j;
                }
        }    
        exit(EXIT_SUCCESS);
}

I could think of one way: passing a pointer to a pointer:

void foo_a(int m, int n, int **ptr_arr)
{
        int i, j;
        for (i = 0; i < m; i++) {
                for (j = 0; j < n; j++) {
                        ptr_arr[i][j] += 1;
                }
                printf("\n");
        }
}

But that would involve flattening the array first by inserting something like into main (which is not pretty).

int *unidim_arr[ROW];
for (i = 0; i < ROW; i++) {
        unidim_arr[i] = &(arr[i][0]);
}

Another one would probably be using a single pointer and calculating the offset by hand which is error prone:

void foo_b(int m, int n, int *ptr_arr)
{
        int i, j;
        for (i = 0; i < m; i++) {
                for (j = 0; j < n; j++) {
                         *((ptr_arr + i * n) + j) += 1;
                }
        }
}

The solution that strikes me as nicest is using something like

void foo_c(int m, int n, int (*ptr_arr)[])
{
        int i, j;
        for (i = 0; i < m; i++) {
                for (j = 0; j < n; j++) {
                        ptr_arr[i][j] += 1;
                }
        }
}

but to my understanding this would only work with VLAs where I can simply specify (*ptr_arr)[n] in the functions parameter list? Is there another way to do it in c90 with special attention to foo_c()?

1. Please, no systemd-bashing.

Upvotes: 2

Views: 577

Answers (1)

John Bode
John Bode

Reputation: 123548

One method is to pass a pointer to the first element of the array along with the array dimensions, then treat that pointer as a 1-d array in your function.

Example:

void foo( int *arr, size_t r, size_t c )  // process a 2D array defined as int arr[r][c]
{
  for ( size_t i = 0; i < r; i++ )
    for ( size_t j = 0; j < c; j++ )
      arr[i * r + j] = some_value();  // calculate index manually
}

int main( void )
{
  int arr[4][5];

  foo( &arr[0][0], 4, 5 );
}

This scales up pretty easily to higher dimensioned arrays. Naturally this only works for true multi-dimensional arrays where the rows are all adjacent in memory. This won't work for arrays dynamically allocated a row at a time, such as

int **arr = malloc( sizeof *arr * rows );
for ( size_t i = 0; i < rows; i++ )
  arr[i] = malloc( sizeof *arr[i] * cols );

since the rows aren't guaranteed to be adjacent, but in that case you'd just use the arr pointer as-is:

void bar( int **arr, size_t r, size_t c ) // process a 2D array defined as int **arr
{
  for ( size_t i = 0; i < r; i++ )
    for ( size_t j = 0; j < c; j++ )
      arr[i][j] = some_value();
}

Upvotes: 2

Related Questions