Search code examples
callocgeneric-collections

template style matrix implementation in c


From time to time I use the following code for generating a matrix style datastructure

typedef double myType;

typedef struct matrix_t{                                                             |Compilation started at Mon Apr  5 02:24:15
  myType **matrix;                                                                   |
  size_t x;                                                                          |gcc structreaderGeneral.c -std=gnu99 -lz
  size_t y;                                                                          |
}matrix;                                                                             |Compilation finished at Mon Apr  5 02:24:15
                                                                                     |
                                                                                     |
matrix alloc_matrix(size_t x, size_t y){                                             |
  if(0)                                                                              |
    fprintf(stderr,"\t-> Alloc matrix with dim (%lu,%lu) byteprline=%lu bytetotal:%l\|
u\n",x,y,y*sizeof(myType),x*y*sizeof(myType));                                       |
                                                                                     |
  myType **m = (myType **)malloc(x*sizeof(myType **));                               |
  for(size_t i=0;i<x;i++)                                                            |
    m[i] =(myType *) malloc(y*sizeof(myType *));                                     |
                                                                                     |
  matrix ret;                                                                        |
  ret.x=x;                                                                           |
  ret.y=y;                                                                           |
  ret.matrix=m;                                                                      |
  return ret;                                                                        |
} 

And then I would change my typedef accordingly if I needed a different kind of type for the entries in my matrix.

Now I need 2 matrices with different types, an easy solution would be to copy/paste the code, but is there some way to do a more generic implementation.

Thanks

edit: I should clarify that its in c not c++. Sorry for not making that clear.


Solution

  • In C? Messy, but possible with macro magic. (You're getting to the point where C++ is a better choice, BTW).

    #define DECL_MATRIX(type,name) \
        typedef struct matrix_##type##_t {             \
            type **matrix;                             \
            size_t x;                                  \
            size_t y;                                  \
        } name;                                        \
        name alloc_##name(size_t x,size_t y)
    
    #define DEFINE_MATRIX_OPS(type,name) \
        struct matrix_##type##_t                       \
        alloc_##name(size_t x, size_t y) {             \
            size_t i;                                  \
            struct matrix_##type##_t ret;              \
            type **m;                                  \
                                                       \
            m = (type **)malloc(x*sizeof(type *));     \
            for(size_t i=0;i<x;i++)                    \
                m[i] =(type *) malloc(y*sizeof(type)); \
            ret.x=x;                                   \
            ret.y=y;                                   \
            ret.matrix=m;                              \
            return ret;                                \
        }
    

    You'd then use these like this:

    // At the top level of the file
    DECL_MATRIX(double, dmat);
    DECL_MATRIX(int, imat);
    DEFINE_MATRIX_OPS(double, dmat);
    DEFINE_MATRIX_OPS(int, imat);
    
    // In a function
    dmat d = alloc_dmat(3,3);
    imat i = alloc_imat(2,6);
    

    As a design note, it's better for matrixes of a fixed size to allocate the memory for the elements as a single block and to use a little math to index into them. Thus instead of ary[a][b] you use ary[a*x_size+y]. You can wrap this all up in more macros if you want, but it is much more efficient, both in terms of memory management and access.