Sign in to follow this  
sheep19

dynamically allocating a 2D array

Recommended Posts

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
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[i] = new int[y];

Share this post


Link to post
Share on other sites
Quote:
Original post by sheep19
I have two matrices that I need to multiply. The matrices's dimensions are known in run-time

Why aren't the dimensions known at compile time, what do these matrices represent?

Share this post


Link to post
Share on other sites
In past (long long days ago) I made an C program to to do matrix operation in this way. I can share you my full code.

although its written it would compile in C and you can group all these functions in a Matrix Class.

Here I've not used structure you can use.

However I think It would help you.

You can copy paste this code and it would compile.

#include <stdio.h>

int mat_get(int** m, int row, int col, int i, int j);
void mat_set(int** m, int row, int col, int i, int j, int val);
void mat_fill(int** m, int row, int col, int num);
void mat_fill_zero(int** m, int row, int col);
void mat_identity(int** m, int row, int col);
void mat_add(int** m, int** n, int** res, int row, int col);
void mat_sub(int** m, int** n, int** res, int row, int col);
void mat_printf(int** m, int row, int col);
void mat_scanf(int** m, int row, int col);
int mat_mult(int** m, int** n, int** res, int r1, int c1, int r2, int c2);
void mat_mult_scaler(int** m, int** res, int r, int c, int num);
void mat_transpose(int** m, int** res, int r, int c);

int main(){
int x[6], y[2][3], z[2][3], a[2][3];
int m[2][3] = {{3, -1, -2},{2, -2, -1}};
int n[3][3] = {{4, 2, 0}, {3, 0, 2}, {1, 1, 0}};
int t[3][2];

mat_fill_zero(&y, 2, 3);
mat_fill(&y, 2, 3, 4);
mat_fill(&z, 2, 3, 5);
mat_scanf(&z, 2, 3);
mat_add(&y, &z, &a, 2, 3);
mat_printf(&a, 2, 3);
printf("\n---------------\n\n");
mat_mult(&m, &n, &a, 2, 3, 3, 3);
mat_printf(&a, 2, 3);
mat_mult_scaler(&a, &a, 2, 3, 2);
printf("\n---------------\n\n");
mat_printf(&a, 2, 3);
mat_transpose(&a, &t, 2, 3);
printf("\n---------------\n\n");
mat_printf(&t, 3, 2);
return 0;
}

/**
get an element of i, j location of a matrix
e.g. mat_get(m, row, col, i, j) can be used to get the [i][j] element of the matrix
you must provide the size e.g. row and column of that matrix through row and col params
*/

int mat_get(int** m, int row, int col, int i, int j){
return ((int)*(m + ((i*col)+j)));
}

/**
same as mat_get() used for changing element of that location
*/

void mat_set(int** m, int row, int col, int i, int j, int val){
*(m + ((i*col)+j)) = val;
}

/**
makes all elements of a 2d array Zero
*/

void mat_fill_zero(int** m, int row, int col){
mat_fill(m, row, col, 0);
}

/**
Identity Matrix
*/

void mat_identity(int** m, int row, int col){
mat_fill(m, row, col, 1);
}

/**
fills the matrix with the provided integer
*/

void mat_fill(int** m, int row, int col, int num){
int i=0, j=0;
for(i=0;i<row;i++){
for(j=0;j<col;j++){
mat_set(m, row, col, i, j, num);
}
}
}

/**
add two matrixes
*/

void mat_add(int** m, int** n, int** res, int row, int col){
int i=0, j=0, num;
for(i=0;i<row;i++){
for(j=0;j<col;j++){
num = mat_get(m, row, col, i, j) + mat_get(n, row, col, i, j);
mat_set(res, row, col, i, j, num);
}
}
}

/**
subtract two matrixes
*/

void mat_sub(int** m, int** n, int** res, int row, int col){
int i=0, j=0, num;
for(i=0;i<row;i++){
for(j=0;j<col;j++){
num = mat_get(m, row, col, i, j) - mat_get(n, row, col, i, j);
mat_set(res, row, col, i, j, num);
}
}
}

/**
prints Elements of a matrix
*/

void mat_printf(int** m, int row, int col){
int i=0, j=0;
for(;i<row;i++){
for(j=0;j<col;j++){
printf("%4d", mat_get(m, row, col, i, j));
if(j != col-1){
printf(" |");
}
}
printf("\n");
}
}

/**
gets elements of a matrix by scanf
*/

void mat_scanf(int** m, int row, int col){
int i=0, j=0, num;
for(;i<row;i++){
printf("Row [%d]\n", i);
for(j=0;j<col;j++){
printf("\telement [%d][%d]:\t", i, j);
scanf("%d", &num);
mat_set(m, row, col, i, j, num);
}
printf("\n");
}
}

/**
Matrix Multiplication
*/

int mat_mult(int** m, int** n, int** res, int r1, int c1, int r2, int c2){
int i=0, j=0, num, r=0;
if(r2 != c1)return 0;
for(;i<r1;i++){
for(j=0;j<c2;j++){
num=0;
r=0;
while(r <= r1){
num += mat_get(m, r1, c1, i, r)*mat_get(n, r2, c2, r, j);
r++;
}
mat_set(res, r1, c2, i, j, num);
}
}
return 1;
}

/**
Multiply a matrix with a scaler number
*/

void mat_mult_scaler(int** m, int** res, int r, int c, int num){
int i=0, j=0;
for(;i<r;i++){
for(j=0;j<c;j++){
mat_set(res, r, c, i, j, mat_get(m, r, c, i, j)*num);
}
}
}

/**
transpose of a matrix
*/

void mat_transpose(int** m, int** res, int r, int c){
int i=0, j=0;
for(;i<c;i++){
for(j=0;j<r;j++){
mat_set(res, c, r, i, j, mat_get(m, r, c, j, i));
}
}
}


Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this