Click here to Skip to main content
15,886,036 members
Articles / Programming Languages / C++
Article

2D Matrix Container with [][] indexing

Rate me:
Please Sign up or sign in to vote.
4.00/5 (7 votes)
5 Jun 20021 min read 153.5K   2.3K   25   25
This article presents a 2D Matrix container with [][] indexing. Indexing works as if you had overloaded the mythical operator [][].

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;
}

License

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


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

Comments and Discussions

 
Generalnice article Pin
lxz20889-May-06 23:03
lxz20889-May-06 23:03 
GeneralContainer loading heuristic algorithm Pin
rajeshdara25-Mar-06 6:32
rajeshdara25-Mar-06 6:32 
GeneralRow and Cols Pin
schnufftrax5-Jan-05 21:55
schnufftrax5-Jan-05 21:55 
Generaloperator[] Pin
Member 124058822-Oct-04 2:54
Member 124058822-Oct-04 2:54 
GeneralRe: operator[] Pin
Alex Chirokov31-Oct-04 11:35
Alex Chirokov31-Oct-04 11:35 
GeneralVisual C++ (MFC) : Using Matrix to set an part of an image to zero Pin
pohcb_sonic15-Sep-04 16:36
pohcb_sonic15-Sep-04 16:36 
GeneralMany thanks Pin
Aris Adrianto Suryadi13-Mar-04 18:11
Aris Adrianto Suryadi13-Mar-04 18:11 
GeneralTemplate-Based Helper Classes Pin
Mo Hossny9-Mar-04 3:31
Mo Hossny9-Mar-04 3:31 
General3D Matrix Pin
macmac388-Oct-03 10:32
macmac388-Oct-03 10:32 
GeneralRe: 3D Matrix Pin
Mo Hossny9-Mar-04 3:26
Mo Hossny9-Mar-04 3:26 
GeneralRe: 3D Matrix Pin
Aris 4 fun13-Mar-04 18:18
sussAris 4 fun13-Mar-04 18:18 
GeneralRe: 3D Matrix Pin
Mo Hossny13-Mar-04 20:48
Mo Hossny13-Mar-04 20:48 
GeneralRe: 3D Matrix Pin
ninangel8-Oct-04 15:31
ninangel8-Oct-04 15:31 
GeneralRe: 3D Matrix Pin
Mo Hossny9-Oct-04 8:12
Mo Hossny9-Oct-04 8:12 
QuestionDefensive ? Pin
killer_bass11-Jun-02 7:44
killer_bass11-Jun-02 7:44 
AnswerRe: Defensive ? Pin
Alex_Chirokov21-Aug-03 7:58
sussAlex_Chirokov21-Aug-03 7:58 
GeneralGood Job! Pin
WREY8-Jun-02 1:46
WREY8-Jun-02 1:46 
GeneralMatrix Template Library Pin
Jonathan de Halleux6-Jun-02 4:29
Jonathan de Halleux6-Jun-02 4:29 
Check MTL for matrix stuff. It has all you need. Among others :
- STL syntax, compatibility,
- Interface to Lapack,

http://www.osl.iu.edu/research/mtl/

Jonathan de Halleux, Belgium.

GeneralRe: Matrix Template Library Pin
Ernest Laurentin6-Jun-02 5:00
Ernest Laurentin6-Jun-02 5:00 
GeneralRe: Matrix Template Library Pin
Jonathan de Halleux6-Jun-02 5:14
Jonathan de Halleux6-Jun-02 5:14 
GeneralRe: Matrix Template Library Pin
Bartosz Bien24-Feb-04 22:14
Bartosz Bien24-Feb-04 22:14 
GeneralRe: Matrix Template Library Pin
Jonathan de Halleux24-Feb-04 23:29
Jonathan de Halleux24-Feb-04 23:29 
GeneralNice feature, fair article Pin
Ed Gadziemski6-Jun-02 3:37
professionalEd Gadziemski6-Jun-02 3:37 
GeneralSome thoughts Pin
6-Jun-02 0:05
suss6-Jun-02 0:05 
GeneralRe: Some thoughts Pin
John M. Drescher8-Jun-02 0:02
John M. Drescher8-Jun-02 0:02 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

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