تنفيذ مصفوفة نمط القالب في ج
-
24-09-2019 - |
سؤال
من وقت لآخر ، أستخدم الكود التالي لإنشاء بنية بيانات نمط المصفوفة
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; |
}
وبعد ذلك أود تغيير typedef الخاص بي وفقًا لذلك إذا كنت بحاجة إلى نوع مختلف من النوع للإدخالات في المصفوفة الخاصة بي.
الآن أحتاج إلى مصفوفين مع أنواع مختلفة ، سيكون الحل السهل هو نسخ/لصق الكود ، ولكن هل هناك طريقة لفعل تنفيذ أكثر عاما.
شكرًا
تحرير: يجب أن أوضح أنه في C ليس C ++. آسف لعدم توضيح ذلك.
المحلول
في ج؟ فوضوي ، ولكن ممكن مع Macro Magic. (أنت تصل إلى النقطة التي يكون فيها C ++ خيارًا أفضل ، راجع للشغل).
#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; \
}
ثم تستخدم هذا مثل هذا:
// 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);
كملاحظة تصميم ، من الأفضل بالنسبة لمصفوفات الحجم الثابت لتخصيص الذاكرة للعناصر ككتلة واحدة واستخدام القليل من الرياضيات للفهرس فيها. وهكذا بدلا من ary[a][b]
انت تستخدم ary[a*x_size+y]
. يمكنك لف كل هذا في المزيد من وحدات الماكرو إذا كنت تريد ، لكنها أكثر كفاءة ، سواء من حيث إدارة الذاكرة والوصول إليها.
نصائح أخرى
كنت بحاجة إلى مصفوفة بسيطة للغاية لمشروع لمرة واحدة وطرق هذا المشروع. هذا ليس ما أسميه جودة الإنتاج ، لكنه قد يمنحك بعض الأفكار:
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;
};
كما هو مقترح في التعليقات السابقة ، مصفوفة صف ماجور باستخدام الذاكرة الخطية:
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];
}