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
开发者_JS百科 |
|
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.
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.
I needed a very simple matrix for a one-off project and knocked this one up. It's not what I would call production quality, but it may give you some ideas:
template <typename T>
class Matrix2D {
public:
Matrix2D( unsigned int width, unsigned int height,
const T & v = T() ) {
if ( width == 0 || height == 0 ) {
throw std::out_of_range( "Invalid Matrix2D size ");
}
for ( unsigned int x = 0; x < width; x++ ) {
mData.push_back( std::vector<T>( height, v ) );
}
}
T & operator()( unsigned int x, unsigned int y ) {
if ( x >= Width() || y >= Height() ) {
throw std::range_error( "Invalid Matrix2D index" );
}
return mData[x][y];
}
const T & operator()( unsigned int x, unsigned int y ) const {
if ( x >= Width() || y >= Height() ) {
throw std::range_error( "Invalid Matrix2D index" );
}
return mData[x][y];
}
void Clear( const T & v = T() ) {
for ( unsigned int x = 0; x < Width(); x++ ) {
for ( unsigned int y = 0; y < Height(); y++ ) {
mData[x][y] = v;
}
}
}
unsigned int Width() const {
return mData.size();
}
unsigned int Height() const {
return mData[0].size();
}
void DumpOn( std::ostream & os ) {
for ( unsigned int y = 0; y < Height(); y++ ) {
for ( unsigned int x = 0; x < Width(); x++ ) {
os << '[' << mData[x][y] << ']';
}
os << "\n";
}
}
private:
std::vector <std::vector <T> > mData;
};
As suggested on previous comments, a row-major matrix using linear memory:
template<typename T, unsigned int DIM>
class matrix {
public:
matrix<T,DIM>() {
matrix(0);
}
matrix<T,DIM>(const T* v) {
for (unsigned int i=0; i<DIM*DIM; ++i)
value[i] = v[i];
}
matrix<T,DIM>(T v) {
for (unsigned int i=0; i<DIM*DIM; ++i)
value[i] = v;
}
T& operator[](int index) {
assert(index >= 0 && index < (int)(DIM*DIM));
return value[index];
}
// and so on...
private:
T value[DIM * DIM];
}
精彩评论