dynamically allocating a 2D array

This topic is 3723 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

How can I dynamically allocate a 2D array? (the dimensions are gained in runtime)

Share on other sites
In what language?

Sorry, C++.

Share on other sites
There is boost::multi_array.

Share on other sites
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:

&lt;matrix.h&gt;#ifndef MATRIX_H#define MATRIX_H#include &lt;iostream&gt;#include &lt;ostream&gt;#include &lt;string&gt;#include &lt;sstream&gt;#include &lt;vector&gt;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*/	}}

Share on other sites
Quote:
 Original post by sheep19and 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];}

Share on other sites
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).

Share on other sites
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 */

Share on other sites
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];

Share on other sites
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.

• What is your GameDev Story?

In 2019 we are celebrating 20 years of GameDev.net! Share your GameDev Story with us.

• 10
• 11
• 13
• 9
• 11
• Forum Statistics

• Total Topics
634088
• Total Posts
3015449
×