Reputation: 5970
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
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