dynamically allocating a 2D array

Started by
13 comments, last by nlbs 15 years, 5 months ago
How can I dynamically allocate a 2D array? (the dimensions are gained in runtime)
Advertisement
In what language?
Sorry, C++.
There is boost::multi_array.
Is there a way to do it just by using the standard template library?

I have two matrices that I need to multiply. The matrices's dimensions are known in run-time so I use a pointer.

e.g: If it's a 2x2 matrix I do:
p /*a pointer*/ = new int[x*y];

and I do things like this to access the values:
*(p + (i * y) + j)

But it gets too complicated to multiply the matrices.

It would be nice if there was a constant expression thing, like C++0x is going to have. Is there such thing in C++?

If not, I would like to use a 2D array, dynamically allocated. Can I do this? Or do I have to use boost?

Here is my class by the way:

<matrix.h>#ifndef MATRIX_H#define MATRIX_H#include <iostream>#include <ostream>#include <string>#include <sstream>#include <vector>enum TYPE { ADD = 0, SUBTRACT, MULTIPLY };class Matrix{public:	Matrix(int x, int y);	Matrix(Matrix &m);	~Matrix();	void Init();	void Display() const;	Matrix& operator = (const Matrix &m);		Matrix& operator += (const Matrix &m);	Matrix& operator -= (const Matrix &m);	Matrix& operator *= (const Matrix &m);	//**************** PUBLIC STATIC MEMBER FUNCTIONS ********************************	// create a new matrix by adding/subtracting/multiplying 2 matrices	static Matrix* CreateMatrix(const Matrix &a, const Matrix &b, int type);	// free memory occupied by CreateMatrix()	static int ReleaseMatrix(Matrix *m);	// returns true if an addition, subtraction or multiplication can be done	static bool Can_Add_Subtract_Multiply(const Matrix &a, const Matrix &b, int type);private:	//set the values of the newly created matrix (called by CreateMatrix()	static void Matrix::setValues(Matrix *pMatrix, const Matrix &a, const Matrix &b, int type);	/***********************************************************************************************/		/* if the matrix has been given values through init() and assignment operator it's true		it is required for the matrix to be displayed in Display() */	bool isInitialized; 	int x, y;	int *p; // pointer to the matrix};#endif // MATRIX_H


matrix.cpp
#include "matrix.h"Matrix::Matrix(int x, int y): x(x), y(y), isInitialized(false){	if( x && y)		p = new int[x * y];	else		exit(1);}Matrix::~Matrix(){	delete p;}void Matrix::Init(){	isInitialized = true;	int num;	for(int i = 0; i < x; ++i)	{		for(int j = 0; j < y; ++j)		{			std::cout << "Enter number " << i+1 << ", " << j+1 << ": ";			std::cin >> num;			*(p + (i * y) + j) = num;		}	}	std::cout << "\n";}void Matrix::Display() const{	if(isInitialized)	{		std::cout << "Matrix:\n";		for(int i = 0; i < x; ++i)		{			for(int j = 0; j < y; ++j)			{				std::cout << " " << *(p + (i * y) + j);				if(j != y - 1)					std::cout << "\t";							}			std::cout << "\n";		}			}	else		std::cout << "You must initialize the matrix before displaying it.";		std::cout << "\n";}Matrix& Matrix::operator =(const Matrix &m) // assignment operator{	if(this != &m)	{		isInitialized = true; // set it as initialized		x = m.x;		y = m.y;		delete p; // free the memory that p points to		p = new int[x * y]; // allocate memory		for(int i = 0; i < x * y; ++i) // get the values			*(p + i) = *(m.p + i);	}	return *this;}Matrix& Matrix::operator +=(const Matrix &m){		if(x == m.x && y == m.y)	{		isInitialized = true;		for(int i = 0; i < x; ++i)		{			for(int j = 0; j < y; ++j)			{				*(p + (i * y) + j) += *(m.p + (i * y) + j);			}		}	}	return *this;}Matrix& Matrix::operator -=(const Matrix &m){	if(x == m.x && y == m.y)	{		isInitialized = true;		for(int i = 0; i < x; ++i)		{			for(int j = 0; j < y; ++j)			{				*(p + (i * y) + j) -= *(m.p + (i * y) + j);			}		}	}	return *this;}Matrix& Matrix::operator *=(const Matrix &m){	if(x == m.x && y == m.y)	{		isInitialized = true;		for(int i = 0; i < x; ++i)		{			for(int j = 0; j < y; ++j)			{				*(p + (i * y) + j) *= *(m.p + (i * y) + j);			}		}	}	return *this;}Matrix* Matrix::CreateMatrix(const Matrix &a, const Matrix &b, int type){	switch(type)	{	case ADD:	case SUBTRACT:		if(Can_Add_Subtract_Multiply(a, b, type) )		{			Matrix *pMatrix = new Matrix(a.x, a.y); // create a new matrix			setValues(pMatrix, a, b, type); // give it values			pMatrix->isInitialized = true; // set is as initialized			return pMatrix;		}		break;	case MULTIPLY:		if(Can_Add_Subtract_Multiply(a, b, type) )		{			Matrix *pMatrix = new Matrix(a.x, b.y);			setValues(pMatrix, a, b, type);			pMatrix->isInitialized = true;			return pMatrix;		}		break;	default:		return NULL;	}}int Matrix::ReleaseMatrix(Matrix *m){	if(!m) // if NULL		return -1;	else	{		delete m;		m = NULL;		return 0;	}}bool Matrix::Can_Add_Subtract_Multiply(const Matrix &a, const Matrix &b, int type){	switch(type)	{	case ADD:	case SUBTRACT:		return(a.x == b.x && a.y == b.y);	case MULTIPLY:		return(a.y == b.x);	default:		return false;	}}void Matrix::setValues(Matrix *pMatrix, const Matrix &a, const Matrix &b, int type){	switch(type)	{	case ADD:		for(int i = 0; i < a.x * a.y; ++i)			*(pMatrix->p + i) = (*(a.p + i)) + (*(b.p + i));		break;	case SUBTRACT:		for(int i = 0; i < a.x * a.y; ++i)			*(pMatrix->p + i) = (*(a.p + i)) - (*(b.p + i));		break;		/*				4 1    5 2 4  ===     24   11  18		5 2    4 3 2 ===      33   16  24		*/	case MULTIPLY:		/*arghhhh*/	}}
Quote:Original post by sheep19
and I do things like this to access the values:
*(p + (i * y) + j)

But it gets too complicated to multiply the matrices.
Why not wrap it up in a function?
value_type get(size_type i, size_type j){    return p[(i * y) + j];}
I think you are vastly overcomplicating it by including too much in a single class. Build small blocks - and use them to make bigger things. Here we use std::vector to make an array2d class, then use that to make our matrix.
template<class T>class array2d{public:    array2d(unsigned w, unsigned h)    :        storage(w * h),        width_(w)    {    }    unsigned width() const { return width_; }    unsigned height() const { return storage.size() / width_; }    T &operator()(unsigned x, unsigned y)    {        return storage[index(x,y)];    }    const T &operator()(unsigned x, unsigned y) const    {        return storage[index(x,y)]);    }private:    std::vector<T> storage;    unsigned width_;    unsigned index(unsigned x, unsigned y)    {        return (y * width_) + x;    }};class Matrix{public:    Matrix(unsigned w, unsigned h)    :         storage(w,h)    {    }    T &operator()(unsigned x, unsigned y)    {        return storage(x,y);    }    const T &operator()(unsigned x, unsigned y) const    {        return storage(x,y);    }private:    array2d<int> storage;};Matrix operator+(const Matrix &a, const Matrix &b){     // check that dimensions are sane          // implement code     // use result(x,y) = a(x,y) + b(x,y)}// more functions...

Note how we don't need to implement destructors or assignment operators, because we make use of std::vector which does this for us.


I would advise against functions like Can_Add_Subtract_Multiply() and setValues() - they are too complicated. It is easier to write separate functions for each case.

Also, I would advised against having a "uninitialised" state. I can only see bad things coming from this.

Calling exit() when passed invalid arguments is a very poor decision IMO. Better to use assert() or an exception (probably an exception if the dimensions are created at run time).
Thanks for the advice. I'm going to use a double pointer.

int **pp = new int[x];for(int i = 0; i < x; ++i)   *(pp + i) = new int[y];


But first I'll make a class and use templates.

Thanks for the help!

/*looking for template tutorials */
You don't need to use a double pointer. Doing so will unnecessarily fragment memory. However, should you for some reason decide to do that then consider using std::vector< std::vector<int> >, rather than deal with manual memory management. Mixing the math functionality with the memory management complicates your class.

Don't abuse pointer arithmetic. It is considerably harder to read than regular array indexing:
for(int i = 0; i < x; ++i)   pp = new int[y];
How would I do it using a vector?

vector < vector<int> > vec;vec.push_back(vector<int>); //getting an errorit works if I create a 1D vector and push it back.

This topic is closed to new replies.

Advertisement