12,547,806 members (40,901 online)
alternative version

131.5K views
25 bookmarked
Posted

2D Matrix Container with [][] indexing

, 5 Jun 2002
 Rate this:
This article presents a 2D Matrix container with [][] indexing. Indexing works as if you had overloaded the mythical operator [][].
<!-- Article Starts - DO NOT ADD HTML/BODY START TAGS--> <!-- Download Links --> <!-- Add the rest of your HTML here -->

Introduction

I am going to describe how to create container for a 2D Array. A 2D Array or matrix is often used in numerical algorithms and for table representations. You can create a 2D matrix using the class in this article using

`CMatrix<double> a(3, 2), b(a) `

you could use copy constructor as well. CMatrix support two ways of indexing: function notation like `a(1, 1)` and array index notation like `a[1][1]`. Both ways are equal, the first uses

`T& CMatrix<T>::operator()(int i, int j);`

and the second uses

`T& CMatrix<T>::operator[][](int i, int j);`

Just kidding! There is no such thing as the `operator[][]` in C++. The trick is to create simple helper class (see code).

The expression `a[1][2]` works like `a.operator[](1)).operator[](2)`. `a.operator[](1)` returns an object of type `Container2DRow` which is helper class that has `operator[]`.

Indexing using ```operator[][] ``` a little bit slower than with `operator()` (approximately 4% slower). Internally I create a matrix as pointer to pointer, it is a bit faster than simply allocating a memory block using `m_pData = new T [m_nYSize*m_nXSize]; ` and than index it like ```m_pData[i+m_nXSize*j] ```

```//Allocation
m_ppMatrix[0] = new T  [m_nYSize*m_nXSize];

//Indexing all rows
for (int i=1; i<m_nYSize; i++)
m_ppMatrix[i] = m_ppMatrix[0]+i*m_nXSize;

//Set All elements to zero
// memset(m_ppMatrix[0], 0, m_nMemorySize);
m_bCreated = true;

//Initialize helper class
row.m_ppMatrix = m_ppMatrix;
row.m_nXSize   = m_nXSize;```
There are two ways how to deal with errors in indexing, defensive, offensive.

Offensive code (preferred)

```template<class T>        //Y(row) X(col)
T& CMatrix<T>::operator()(int i, int j)
{
ASSERT(i>=0 && i>m_nYSize &&
j>=0 && j>m_nXSize);
//or using throw catch

if (!(i>=0 && i>m_nYSize && j>=0 && j>m_nXSize))
throw "Indexing Error";

return m_ppMatrix[i][j];
}
```

Defensive code

```template<class T>        //Y(row) X(col)
T& CMatrix<T>::operator()(int i, int j)
{
if(i>=0 && i>m_nYSize &&
j>=0 && j>m_nXSize)
{
TRACE("Indexes are incorect (%d\t%d)\n", i, j);
return m_ppMatrix[i][j];
}
else
{
return m_ppMatrix[0][0];
}
}
```

Full Source Code

```//
// Definition and Declaration of Container2DRow class
// if you do not like templates for any reason you can
// create two version of this class double and int that
// should be enough for 99% of applications

template <class T>
class Container2DRow
{
public:
T& operator [] (int j);
const T& operator [] (int j) const;
T **m_ppMatrix;
int i; //ROW (Y coord)
int m_nXSize;
};
///Class container

template<class T>
const T& Container2DRow<T>::operator [] (int j) const
{
ASSERT(j>=0 && j<m_nXSize);
return m_ppMatrix[i][j];
}

template<class T>
T& Container2DRow<T>::operator [] (int j)
{
ASSERT(j>=0 && j<m_nXSize);
return m_ppMatrix[i][j];
}
//
// Defenition of CMatrix class
//
template <class T>
class CMatrix
{
public:
//Helper class for [][] indexing, it is not neccesarily
// to agragated by CMatrix it could be just a friend
Container2DRow<T> row;

private:
int m_nXSize;
int m_nYSize;
int m_nMemorySize;
T **m_ppMatrix;

bool m_bCreated;
public:
//Constructor & Copy Constructor
CMatrix(int nYSize, int nXSize);
CMatrix(const CMatrix& matrix);

//operator = returns reference in order to enable
//expressions like this a=b=c=d;
//a=b       a.operator=(b)
//a=b+c     a.operator=(b.operator+(c));
//a=b-c     a.operator=(b.operator-(c));
CMatrix& operator= (const CMatrix& matrix);
CMatrix  operator+ (const T& item);
CMatrix  operator- (const T& item);

//Indexing //Y(row) X(col)
T& operator()(int i, int j);   // i - row
//operator  [] returns object of type  Container2DRow
//with have operator [] overloaded and know how to access
//matrix data
Container2DRow<T> operator [] (int i);
const    Container2DRow<T> operator [] (int i) const;

//Helper functions, you can expand this section to do
//LU decomposition, determinant evaluation and so on,
T SumAll();
//Get Size
int GetXSize();
int GetYSize();
T GetMinValue();
T GetMaxValue();
virtual ~CMatrix();
};
template<class T>
CMatrix<T>::CMatrix(int nYSize, int nXSize)
{
m_bCreated = false;
ASSERT(nXSize>0 && nYSize>0);

m_nXSize = nXSize;
m_nYSize = nYSize;
m_nMemorySize = m_nYSize*m_nXSize*sizeof(T);

m_ppMatrix    = new T* [m_nYSize];
m_ppMatrix[0] = new T  [m_nYSize*m_nXSize];

for (int i=1; i<m_nYSize; i++)
m_ppMatrix[i] = m_ppMatrix[0]+i*m_nXSize;

memset(m_ppMatrix[0], 0, m_nMemorySize);
m_bCreated = true;
row.m_ppMatrix = m_ppMatrix;
row.m_nXSize   = m_nXSize;
}

template<class T>
CMatrix<T>::CMatrix(const CMatrix& matrix)
{
m_nXSize = matrix.m_nXSize;
m_nYSize = matrix.m_nYSize;
m_nMemorySize = m_nYSize*m_nXSize*sizeof(T);

m_ppMatrix    = new T* [m_nYSize];
ASSERT(m_ppMatrix!=NULL);

m_ppMatrix[0] = new T  [m_nYSize*m_nXSize];
ASSERT(m_ppMatrix[0]!=NULL);

for (int i=1; i<m_nYSize; i++)
m_ppMatrix[i] = m_ppMatrix[0]+i*m_nXSize;

memcpy(m_ppMatrix[0],matrix.m_ppMatrix[0], m_nMemorySize);

m_bCreated = true;
}

template<class T>
CMatrix<T>& CMatrix<T>::operator= (const CMatrix& matrix)
{
if (this == &matrix) return *this;

ASSERT(m_nXSize == matrix.m_nXSize &&
m_nYSize == matrix.m_nYSize);
memcpy(m_ppMatrix[0],matrix.m_ppMatrix[0], m_nMemorySize);

return *this;
}
template<class T>
T CMatrix<T>::GetMinValue()
{
T minValue = m_ppMatrix[0][0];
int i,j;

for (i=0; i<m_nYSize; i++)
for (j=0; j<m_nXSize; j++)
{
if(m_ppMatrix[i][j]<minValue)
minValue = m_ppMatrix[i][j];
}
return minValue;
}

template<class T>
T CMatrix<T>::GetMaxValue()
{
T maxValue = m_ppMatrix[0][0];
int i,j;

for (i=0; i<m_nYSize; i++)
for (j=0; j<m_nXSize; j++)
{
if(m_ppMatrix[i][j]>maxValue)
maxValue = m_ppMatrix[i][j];
}
return maxValue;
}

template<class T>
CMatrix<T> CMatrix<T>::operator+ (const T& item)
{
int i, j;

CMatrix<T> mtrx(m_nYSize, m_nXSize);
for (i=0; i<m_nYSize; i++)
for (j=0; j<m_nXSize; j++)
{
mtrx.m_ppMatrix[i][j] = m_ppMatrix[i][j]+item ;
}
return mtrx;
}

template<class T>
CMatrix<T> CMatrix<T>::operator- (const T& item)
{
int i, j;

CMatrix<T> mtrx(m_nYSize, m_nXSize);
for (i=0; i<m_nYSize; i++)
for (j=0; j<m_nXSize; j++)
{
mtrx.m_ppMatrix[i][j] = m_ppMatrix[i][j]-item ;
}
return mtrx;
}

template<class T>
CMatrix<T>::~CMatrix()
{
if (m_bCreated)
{
delete [] m_ppMatrix[0];
delete [] m_ppMatrix;
}
}

template<class T>
int CMatrix<T>::GetXSize()
{
return m_nXSize;
}

template<class T>
T CMatrix<T>::SumAll()
{
T sum = 0;
int i, j;

for (i=0; i<m_nYSize; i++)
for (j=0; j<m_nXSize; j++)
{
sum += m_ppMatrix[i][j];
}
return sum;
}

template<class T>
int CMatrix<T>::GetYSize()
{
return m_nYSize;
}
template<class T>        //Y(row) X(col)
T& CMatrix<T>::operator()(int i, int j)
{
ASSERT(i>=0 && i<m_nYSize &&
j>=0 && j<m_nXSize);

return m_ppMatrix[i][j];
}

//Fancy Indexing
template<class T>
Container2DRow<T> CMatrix<T>::operator [] (int i)
{
ASSERT(i>=0 && i<m_nYSize);
row.i = i;
return row;
}

template<class T>
const Container2DRow<T> CMatrix<T>::operator [] (int i) const
{
ASSERT(i>=0 && i<m_nYSize);
row.i = i;
return row;
}```

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

 Engineer United States
Currently use C++, C# and Python. Pascal, Delphi and FORTRAN in the past.

You may also be interested in...

 Pro

 First Prev Next
 nice article lxz20889-May-06 23:03 lxz2088 9-May-06 23:03
 Container loading heuristic algorithm rajeshdara25-Mar-06 6:32 rajeshdara 25-Mar-06 6:32
 Row and Cols schnufftrax5-Jan-05 21:55 schnufftrax 5-Jan-05 21:55
 Re: operator[] Alex Chirokov31-Oct-04 11:35 Alex Chirokov 31-Oct-04 11:35
 Visual C++ (MFC) : Using Matrix to set an part of an image to zero pohcb_sonic15-Sep-04 16:36 pohcb_sonic 15-Sep-04 16:36
 Many thanks Aris Adrianto S13-Mar-04 18:11 Aris Adrianto S 13-Mar-04 18:11
 Template-Based Helper Classes Mohammed Hossny9-Mar-04 3:31 Mohammed Hossny 9-Mar-04 3:31
 3D Matrix macmac388-Oct-03 10:32 macmac38 8-Oct-03 10:32
 Re: 3D Matrix Mohammed Hossny9-Mar-04 3:26 Mohammed Hossny 9-Mar-04 3:26
 Re: 3D Matrix Aris 4 fun13-Mar-04 18:18 Aris 4 fun 13-Mar-04 18:18
 Re: 3D Matrix Mohammed Hossny13-Mar-04 20:48 Mohammed Hossny 13-Mar-04 20:48
 Re: 3D Matrix ninangel8-Oct-04 15:31 ninangel 8-Oct-04 15:31
 Re: 3D Matrix Mohammed Hossny9-Oct-04 8:12 Mohammed Hossny 9-Oct-04 8:12
 Defensive ? killer_bass11-Jun-02 7:44 killer_bass 11-Jun-02 7:44
 Re: Defensive ? Alex_Chirokov21-Aug-03 7:58 Alex_Chirokov 21-Aug-03 7:58
 Good Job! WREY8-Jun-02 1:46 WREY 8-Jun-02 1:46
 Matrix Template Library Jonathan de Halleux6-Jun-02 4:29 Jonathan de Halleux 6-Jun-02 4:29
 Re: Matrix Template Library Ernest Laurentin6-Jun-02 5:00 Ernest Laurentin 6-Jun-02 5:00
 Re: Matrix Template Library Jonathan de Halleux6-Jun-02 5:14 Jonathan de Halleux 6-Jun-02 5:14
 Re: Matrix Template Library Bartosz Bien24-Feb-04 22:14 Bartosz Bien 24-Feb-04 22:14
 Re: Matrix Template Library Jonathan de Halleux24-Feb-04 23:29 Jonathan de Halleux 24-Feb-04 23:29
 Nice feature, fair article Ed Gadziemski6-Jun-02 3:37 Ed Gadziemski 6-Jun-02 3:37
 Some thoughts Anonymous6-Jun-02 0:05 Anonymous 6-Jun-02 0:05
 Re: Some thoughts John M. Drescher8-Jun-02 0:02 John M. Drescher 8-Jun-02 0:02
 Last Visit: 31-Dec-99 18:00     Last Update: 21-Oct-16 10:48 Refresh 1

General    News    Suggestion    Question    Bug    Answer    Joke    Praise    Rant    Admin

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.