Jump to content
  • Advertisement
Sign in to follow this  
sheep19

dynamically allocating a 2D array

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

If you intended to correct an error in the post then please contact us.

Recommended Posts

Advertisement
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*/
}
}



Share this post


Link to post
Share on other sites
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];
}

Share this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
Share on other sites
How would I do it using a vector?


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

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!