Here is a way to define a Matrix type
typedef struct {
int nr, nc;
double *elem;
} Matrix;
I would like to define this
typedef struct {
int nr, nc;
double elem[nr][nc];
} Matrix;
It would be nice, because I would not have to worry about indexes. That's the reason VLA are useful in the first place, since they only do transparently what would be easy with index arithmetic.
Of course, the above is not possible, if only because the size of the struct would not be well defined. Then, I would still be happy with:
typedef struct {
int nr, nc;
double (*elem)[nc];
} Matrix;
Now, the matrix data is stored as a pointer, like in the non-VLA case. But the arithmetic could still be done by the compiler. The definition only tells it's some kind of pointer to double
data, with the doubles arranged in an array of width nc
.
It seems that it's not permitted either by the standard, and I wonder why, since it's easy to do the same by transtyping. For example, using the first definition (with double *
), I could do
double get(Matrix *a, int i, int j) {
int nc = a->nc;
double (*p)[nc] = (double (*)[nc])a->elem;
return p[i][j];
}
Of course, it's not very interesting here, since there is only one access to elem, but it could be if there are many.
So, my question, with the hope that it's on topic: what's the very reason of prohibiting the third definition?
I could imagine that it's dangerous since it's not guaranteed that nc
handles the correct value, but this is dangerous anyway with pointers, so it does not look like a good reason.
Does this meet your requirements? It stores a void *
in the structure, and the access functions cast that to a pointer to a 2D VLA and use that. GCC 5.2.0 on Mac OS X 10.10.5 compiles it cleanly, and valgrind
(3.11.0-SVN from November 2014 or thereabouts) gives it a clean bill of health.
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int nr, nc;
void *data; // Actually double a[nr][nc]
} Matrix;
static double get(Matrix *a, int i, int j)
{
double (*array)[a->nr][a->nc] = a->data;
return (*array)[i][j];
}
static void set(Matrix *a, int i, int j, double v)
{
double (*array)[a->nr][a->nc] = a->data;
(*array)[i][j] = v;
}
static Matrix *mat_alloc(int nr, int nc)
{
Matrix *m = malloc(sizeof(*m));
if (m != 0)
{
m->nr = nr;
m->nc = nc;
m->data = malloc(nr * nc * sizeof(double));
if (m->data == 0)
{
free(m);
m = 0;
}
}
return m;
}
static void mat_free(Matrix *m)
{
free(m->data);
free(m);
}
int main(void)
{
int nr = 3;
int nc = 5;
Matrix *m = mat_alloc(nr, nc);
if (m == 0)
{
fprintf(stderr, "Matrix allocation for %dx%d matrix failed\n", nr, nc);
exit(1);
}
for (int i = 0; i < nr; i++)
{
for (int j = 0; j < nc; j++)
{
double v = (i * (nc + 1)) + j + 1;
set(m, i, j, v);
printf("Set: [%d,%d] = %4.1f\n", i, j, v);
}
}
for (int j = 0; j < nc; j++)
{
for (int i = 0; i < nr; i++)
printf("Get: [%d,%d] = %4.1f\n", i, j, get(m, i, j));
}
mat_free(m);
return 0;
}
I'm not sure whether there's a neat way to lose the (*array)
part of the notation in the access functions. I'd prefer it if there was one (other than using array[0][i][j]
, that is).
Set: [0,0] = 1.0
Set: [0,1] = 2.0
Set: [0,2] = 3.0
Set: [0,3] = 4.0
Set: [0,4] = 5.0
Set: [1,0] = 7.0
Set: [1,1] = 8.0
Set: [1,2] = 9.0
Set: [1,3] = 10.0
Set: [1,4] = 11.0
Set: [2,0] = 13.0
Set: [2,1] = 14.0
Set: [2,2] = 15.0
Set: [2,3] = 16.0
Set: [2,4] = 17.0
Get: [0,0] = 1.0
Get: [1,0] = 7.0
Get: [2,0] = 13.0
Get: [0,1] = 2.0
Get: [1,1] = 8.0
Get: [2,1] = 14.0
Get: [0,2] = 3.0
Get: [1,2] = 9.0
Get: [2,2] = 15.0
Get: [0,3] = 4.0
Get: [1,3] = 10.0
Get: [2,3] = 16.0
Get: [0,4] = 5.0
Get: [1,4] = 11.0
Get: [2,4] = 17.0