Pregunta

De vez en cuando uso el siguiente código para generar una datos de estilo matriz

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;                                                                        |
} 

Y luego cambiaría mi typedef en consecuencia si necesitaba un tipo diferente de tipo para las entradas en mi matriz.

Ahora necesito 2 matrices con diferentes tipos, una solución fácil sería copiar/pegar el código, pero hay alguna forma de hacer una implementación más genérica.

Gracias

EDITAR: Debo aclarar que está en c no c ++. Perdón por no dejar eso claro.

¿Fue útil?

Solución

¿Cía? Desordenado, pero posible con Macro Magic. (Estás llegando al punto en que C ++ es una mejor opción, por cierto).

#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;                                \
    }

Entonces los usarías así:

// 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);

Como nota de diseño, es mejor que las matrices de un tamaño fijo asignen la memoria para los elementos como un solo bloque y usen un poco de matemáticas para indexarlos. Así en lugar de ary[a][b] tu usas ary[a*x_size+y]. Puede envolver todo esto en más macros si lo desea, pero es mucho más eficiente, tanto en términos de gestión de memoria como de acceso.

Otros consejos

Necesitaba una matriz muy simple para un proyecto único y lo llamé. No es lo que yo llamaría la calidad de la producción, pero puede darle algunas 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;
};

Como se sugirió en los comentarios anteriores, una matriz de fila-mayor que usa memoria lineal:

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];
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top