How to make easy access to struct as matrix

Viewed 85

I want to create a struct which would be able to have a matrix and some parameters; so, for example, I have:

struct matrix {
    int rows;
    int cols;
    double** data;
} A;

I want to use, instead of A.data[x][y], easy access likeA[x][y] = A.data[x][y]. Any ideas?

2 Answers

i want to make not a A.data[x][y] , but a A[x][y] = A.data[x][y] for easy access. Any ideas?

The members of a struct are accessed through that struct only via the member selection operator (.). They are accessed through a pointer to the struct only via the indirect member selection operator (->). C does not have operator overloading, so the form A[x][y] is not an alternative.

You could create a function or macro to hide the involvement of the data member, but personally, I don't think that would be better or clearer.

It's doable though a bit tricky.

You could use technique similar to one used in Simple Dynamic Strings. Just place metadata before the actual matrix data.

Define your structure like this:

struct matrix {
  int rows, cols;
  double *data[];
};

Allocate it like a typical structure with flexible member.

malloc(sizeof(struct matrix) + rows * sizeof(double*))

Now the twist.

Rather than returning a pointer of struct matrix from matrix_create() return matrix.data, the pointer to member.

double **create_matrix(int rows, int cols) {
  struct matrix *m = malloc( ... );
  ... Allocation of rows
  return m->data;
}

This way you could use nice A[i][j] notation.

Next add a macro to translate this pointer to member back to struct matrix in a similar fashion as container_of. Exemplary implementation.

#define to_matrix(ptr) (struct matrix*)((char*)ptr - offsetof(struct matrix, data))

Now you can implement matrix_get_rows() like this:

int matrix_get_rows(double **A) {
   struct matrix *m = to_matrix(A);
   return m->rows;
}

You can implement similar helpers and destructor in the similar way.

A typical usage could be:

int main() {
  double **A = matrix_create(1,1);
  A[0][0] = 42;
  printf("%d %d\n", matrix_get_rows(A), matrix_get_cols(B));
  // should print "1 1"
  
  matrix_release(A);
  return 0;
}
Related