Reputation: 2945
I have some 3D matrix data that I can access like this: data[x][y][z]
.
The size of each dimension is only known at run-time.
I get this data by casting a malloc with (byte (*)[Y][Z]) malloc(…)
.
When I call this function I know the dimensions of the matrix, but not at compile-time. Thus I don't how I can declare I'm receiving a matrix like this in a function…
What would be the argument type for this data in a function declaration?
function(byte (*matrix)[][]) // doesn't work
Upvotes: 0
Views: 171
Reputation: 754920
Here is some code to illustrate the passing of a 3D array. The 3D array is an array of square matrices which are to be multiplied together to produce the final result. The code is probably not the most efficient possible, but it does illustrate that passing 3D VLA values is not very hard.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void mat_copy(int x, int y, const int src[x][y], int dst[x][y]);
static void mat_list_multiply(int x, int y, const int matlist[*][*][*], int result[*][*]);
static void mat_multiply(int x, int y, int z, const int mat1[*][*], const int mat2[*][*], int result[*][*]);
static void mat_print(const char *tag, int m, int n, const int matrix[*][*]);
int main(void)
{
int matrices[][4][4] =
{
//random -n 48 -- -99 99 | commalist -n 4 -B 12 -b '{ ' -T ' },' -R -W 4
{
{ 63, -61, 36, -27, },
{ 37, -86, 44, -14, },
{ 57, 10, 74, 23, },
{ -74, -52, -87, 53, },
},
{
{ -34, 89, -71, 34, },
{ -68, -44, -89, -95, },
{ -4, -44, 2, 80, },
{ 66, -33, -19, -65, },
},
{
{ -64, 11, 54, 20, },
{ -7, 75, -7, -98, },
{ 52, 48, -96, 76, },
{ -38, -46, -85, 4, },
},
};
enum { NUM_MATRICES = sizeof(matrices) / sizeof(matrices[0]) };
int result[4][4];
mat_list_multiply(3, 4, matrices, result);
for (int i = 0; i < NUM_MATRICES; i++)
{
char name[16];
snprintf(name, sizeof(name), "%s[%d]", "matrices", i);
mat_print(name, 4, 4, matrices[i]);
}
mat_print("result", 4, 4, result);
return 0;
}
static void mat_copy(int x, int y, const int src[x][y], int dst[x][y])
{
memmove(dst, src, x * y * sizeof(src[0][0])); // sizeof(src) is not OK
}
static void mat_list_multiply(int x, int y, const int matlist[x][y][y], int result[y][y])
{
int product[y][y];
mat_copy(y, y, matlist[0], product);
for (int i = 1; i < x; i++)
{
mat_multiply(y, y, y, product, matlist[i], result);
if (i != x-1)
mat_copy(y, y, result, product);
}
}
static void mat_multiply(int x, int y, int z, const int mat1[x][y], const int mat2[y][z], int result[x][z])
{
for (int i = 0; i < x; i++)
{
for (int j = 0; j < z; j++)
{
result[i][j] = 0;
for (int k = 0; k < y; k++)
result[i][j] += mat1[i][k] * mat2[k][j];
}
}
}
static void mat_print(const char *tag, int m, int n, const int matrix[m][n])
{
printf("%s (%dx%d):\n", tag, m, n);
for (int i = 0; i < m; i++)
{
const char *pad = "";
for (int j = 0; j < n; j++)
{
printf("%s%8d", pad, matrix[i][j]);
pad = " ";
}
putchar('\n');
}
}
Output:
matrices[0] (4x4):
63 -61 36 -27
37 -86 44 -14
57 10 74 23
-74 -52 -87 53
matrices[1] (4x4):
-34 89 -71 34
-68 -44 -89 -95
-4 -44 2 80
66 -33 -19 -65
matrices[2] (4x4):
-64 11 54 20
-7 75 -7 -98
52 48 -96 76
-38 -46 -85 4
result (4x4):
-455910 66386 -1265422 -575600
-509373 79435 -1545267 -14906
-392428 -468852 -38119 -464008
137791 727227 393114 1044774
Upvotes: 1
Reputation: 224112
Declare the function with:
function(size_t Y, size_t Z, byte matrix[][Y][Z])…
and call it with:
function(Y, Z, matrix);
C supports variable length arrays (as optional or required depending on version, but support is common in modern compilers), but the called function does not automatically know the dimensions. You have to pass them to the function in some way, and in its declaration, the function has to state the dimensions.
Note that the dimensions can be expressions generally; they do not have to be the exact parameters passed. For example, you could do this:
function(size_t Y, byte matrix[][2*Y][3*Y])…
to declare a function that takes a matrix[something][20][30]
when Y
is 10, for example.
Upvotes: 1