Thread: 2DArray Help

  1. #1
    Registered User
    Join Date
    Aug 2009
    Posts
    36

    2DArray Help

    This is for school.. but I'm not trying to get you guys to do my homework, I've worked pretty hard on this. This is my sixth term of C++ and I'm having trouble making this 2D array work.

    It has a problem in main when I try to set [3][5] to to 'k' but I think this has to do with something in the constructor of Array2D.

    Any help would be greatly appreciated.. Even if you could direct me to a webpage that teaches this sort of thing or just tell me why it isn't working. Feel free to change any code that you like. =).

    Code:
    #include "Array2D.h"
    #include <iostream>
    
    using std::endl;
    using std::cout;
    
    int main()
    {
    	Array2D<char> ok(5, 10);
    	Array2D<char> yeah(3, 8);
    
    	yeah = ok;
    
    	try
    	{
    #error this has a problem too
    		ok[3][5] = 'k';
    	}
    	catch( Exception& e)
    	{
    		cout << e.getMessage() << endl;
    	}
    
    	return 0;
    }
    Code:
    #ifndef ARRAY2D_H
    #define ARRAY2D_H
    
    #include "Array.h"
    #include "Row.h"
    #include "Exception.h"
    
    template <typename T>
    class Array2D
    {
    public:
    	Array2D();
    	Array2D(int row, int col = 0);
    	Array2D(const Array2D<T> &copy);
    	~Array2D();
    	Array2D & operator =(const Array2D<T> & rhs);
    	Row<T> operator [] (int index);
    	int getRow();
    	void setRow( int row );
    	int getColumn();
    	void setColumn( int column );
    	T & Select( int row, int column );
    
    private:
    	SingleArray<T> m_array;
    	int m_row;
    	int m_column;
    };
    
    //Default constructor
    template <typename T>
    Array2D<T>::Array2D() : m_array(0), m_row(0), m_column(0)
    {
    	
    }
    
    //Two arg constructor sets number of rows and columns
    template <typename T>
    Array2D<T>::Array2D(int row, int col = 0) : m_row(row), m_column(col)
    {
    	#error idk how this is supposed to work
    	m_array.setLength( (m_row * m_column) );
    }
    
    //Copy Constructor
    template <typename T>
    Array2D<T>::Array2D(const Array2D &copy)
    {
    	*this = copy;
    }
    
    //Destructor
    template <typename T>
    Array2D<T>::~Array2D()
    {
    	m_row = 0;
    	m_column = 0;
    	m_array = 0;
    }
    
    //Assignment Operator
    template <typename T>
    Array2D<T> & Array2D<T>::operator =(const Array2D & rhs)
    {
    	if(this != &rhs)
    	{
    		m_array.~SingleArray();
    		m_array = rhs.m_array;
    		m_row = rhs.m_row;
    		m_column = rhs.m_column;
    	}
    
    	return *this;
    }
    
    template <typename T>
    Row<T> Array2D<T>::operator [] (int index)
    {
    	if(index > m_row)
    		throw Exception("Index exceeds amount of rows");
    
    	return Row<T>(*this, index);
    }
    
    //Returns the amount of rows
    template <typename T>
    int Array2D<T>::getRow()
    {
    	return m_row;
    }
    
    template <typename T>
    void Array2D<T>::setRow( int row )
    {
    	m_row = row;
    }
    
    //Returns the amount of columns
    template <typename T>
    int Array2D<T>::getColumn()
    {
    	return m_column;
    }
    
    template <typename T>
    void Array2D<T>::setColumn( int column )
    {
    	m_column = column;
    }
    
    template <typename T>
    T & Array2D<T>::Select( int row, int column )
    {
    	return m_array[m_column * row + column];
    }
    #endif
    Code:
    #ifndef SINGLEARRAY_H
    #define SINGLEARRAY_H
    
    #include "Exception.h"
    
    
    /************************************************************************
    * Class: Array
    *
    * Purpose: This class creates a dynamic one-dimensional array that can be * started at any base. 
    *
    * Manager functions:	
    * 	SingleArray ( )
    * 		The default size is zero and the base is zero.  	
    *	SingleArray (int length, int start_index = 0)
    *		Creates an appropriate sized array with the starting index 
    *              either zero or the supplied starting value.
    *	SingleArray (const SingleArray & copy)
    *		Copy constructor which makes a copy of the array
    *	operator = (const SingleArray & copy)
    *		Assignment operator which will assign another type of SingleArray
    *		the properties of the first SingleArray
    *	~SingleArray()
    *		Deconstructor
    *
    * Methods:		
    *	operator [ ] (int index)
    *		returns the index of the array passed in.
    *	int getStartIndex()
    *		returns the start index
    *	void setStartIndex( int start_index)
    *		Sets the start index to the passed in parameter
    *	int getLength()
    *		Returns the length of the array
    *	void SetLength( int length)
    *		Sets the length to the passed in parameter
    *************************************************************************/
    
    template <typename T>
    class SingleArray
    {
    public:
    	SingleArray();
    	SingleArray(int length, int start_index = 0);
    	SingleArray(const SingleArray<T> &copy);
    	~SingleArray();
    	SingleArray<T>& operator = (const SingleArray<T> &rhs);
    	T& operator [] (int index);
    	int getStartIndex();
    	void setStartIndex( int start_index );
    	int getLength();
    	void setLength( int length );
    
    private:
    	T * m_array;
    	int m_length;
    	int m_start_index;
    };
    
    //Default constructor
    template <typename T>
    SingleArray<T>::SingleArray() : m_array(0), m_length(0), m_start_index(0)
    {
    
    }
    
    //Two parameter constructor for setting length and the starting index
    template <typename T>
    SingleArray<T>::SingleArray(int length, int start_index = 0)
    {
    	m_length = length;
    	m_start_index = start_index;
    	m_array = new T[length];
    }
    
    //Copy Constructor
    template <typename T>
    SingleArray<T>::SingleArray(const SingleArray<T> &copy)
    {
    	*this = copy;
    }
    
    //Destructor
    template <typename T>
    SingleArray<T>::~SingleArray()
    {
    	delete [] m_array;
    	m_array = nullptr;
    	m_length = 0;
    	m_start_index = 0;
    }
    
    //Assignment Operator
    template <typename T>
    SingleArray<T> & SingleArray<T>::operator = (const SingleArray<T> &rhs)
    {
    	if(this != &rhs)
    	{
    		delete [] m_array;
    
    		m_array = new T[rhs.m_length];
    
    		for(int i = 0; i < m_length; ++i)
    		{
    			m_array[i] = rhs.m_array[i];
    		}
    
    		m_length = rhs.m_length;
    		m_start_index = rhs.m_start_index;
    	}
    
    	return *this;
    }
    
    //Bracket operator
    template <typename T>
    T & SingleArray<T>:: operator [] (int index)
    {
    	index -= m_start_index;
    
    	if(index < 0)
    		throw Exception("Index lower than minimum");
    	else if(index > m_length)
    		throw Exception("Index higher than maximum");
    
    	return m_array[index];
    }
    
    //Returns the start index
    template <typename T>
    int SingleArray<T>::getStartIndex()
    {
    	return m_start_index;
    }
    
    //Sets the start index to the passed in parameter
    template <typename T>
    void SingleArray<T>::setStartIndex( int start_index )
    {
    	m_start_index = start_index;
    }
    
    //Returns the length of the array
    template <typename T>
    int SingleArray<T>::getLength()
    {
    	return m_length;
    }
    
    //Sets the length of the array to the passed in parameter
    template <typename T>
    void SingleArray<T>::setLength( int length )
    {
    	m_length = length;
    }
    
    #endif
    Code:
    #ifndef ROW_H
    #define ROW_H
    
    template <typename T>
    class Array2D;
    
    template <typename T>
    class Row
    {
    public:
    	Row(Array2D<T> & Array, int row);
    	T & operator [] ( int column);
    private:
    	Array2D<T> & m_array2D;
    	int m_row;
    };
    #endif
    
    template <typename T>
    Row<T>::Row(Array2D<T> & Array, int row) : m_array2D(Array), m_row(row)
    {
    
    }
    
    template <typename T>
    T & Row<T>::operator[](int column)
    {
    	if( column > m_array2D.getColumn() )
    		throw Exception("Index exceeds amount of columns");
    
    	return m_array2D.Select(m_row, column);
    }

  2. #2
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    In SingleArray:

    You need to do more than this to create a proper copy (such as properly delete the currently allocated memory for this and create an actual copy of copy's data).
    Code:
    template <typename T>
    SingleArray<T>::SingleArray(const SingleArray<T> &copy)
    {
    	*this = copy;
    }

    You're not handling m_length properly here:
    Code:
    template <typename T>
    SingleArray<T> & SingleArray<T>::operator = (const SingleArray<T> &rhs)
    {
    	if(this != &rhs)
    	{
    		delete [] m_array;
    
    		m_array = new T[rhs.m_length];
    
    		for(int i = 0; i < m_length; ++i)
    		{
    			m_array[i] = rhs.m_array[i];
    		}
    
    		m_length = rhs.m_length;
    		m_start_index = rhs.m_start_index;
    	}
    
    	return *this;
    }

    This should be index >= m_length
    Code:
    	else if(index > m_length)
    		throw Exception("Index higher than maximum");
    Doesn't this
    Code:
    template <typename T>
    void SingleArray<T>::setLength( int length )
    {
    	m_length = length;
    }
    have more work to do? Don't you have to reallocate the space for m_array (presumably copying its current content)?

    That's all I feel like looking at but I have the feeling that there are many more errors.
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  3. #3
    Registered User
    Join Date
    Aug 2009
    Posts
    36
    Well the copy constructor calls the assignment operator so if the assignment opeartor works, then so does the copy constructor but you say the assignment operator doesn't work cuz of m_length? I'm not sure what you mean by that.

    I'll fix the exception snippet and setLength will be fixed momentarily =).

  4. #4
    Registered User
    Join Date
    Aug 2009
    Posts
    36
    New setter
    Code:
    //Sets the length of the array to the passed in parameter
    template <typename T>
    void SingleArray<T>::setLength( int length )
    {
    	if(length < m_length)
    	{
    		T * temp = new T[length];
    
    		for(int i = 0; i < length; ++i)
    		{
    			temp[i] = m_array[i];
    		}
    
    		delete [] m_array;
    
    		m_array = temp;
    
    		m_length = length;
    
    	}
    
    	else if(length == m_length)
    	{
    		m_length = length;
    	}
    
    	else(length > m_length
    	{
    		for(int i = m_length; i < length; ++i)
    		{
    			m_array[i] = new T;
    		}
    		m_length = length;
    	}
    }

  5. #5
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    In setLength you can leave this case out since it changes nothing:
    Code:
    	else if(length == m_length)
    	{
    		m_length = length;
    	}
    This case doesn't make sense:
    Code:
    	else(length > m_length
    	{
    		for(int i = m_length; i < length; ++i)
    		{
    			m_array[i] = new T;
    		}
    		m_length = length;
    	}
    You can't just stick stuff on the end of the array without first making the array bigger.

    And there's a parenthesis missing. Are you even attempting to compile your code?


    As for not handling m_length properly in operator= :
    Code:
    template <typename T>
    SingleArray<T> & SingleArray<T>::operator = (const SingleArray<T> &rhs)
    {
    	if(this != &rhs)
    	{
    		if (m_array) // Ensure not null
    			delete [] m_array;
    
    		m_array = new T[rhs.m_length];
    
    // You're only counting up to the OLD m_length here
    // (which would be a random number if called from the copy ctor)
    		for(int i = 0; i < m_length; ++i)
    		{
    			m_array[i] = rhs.m_array[i];
    		}
    
    // So you should move this next line before the loop
    		m_length = rhs.m_length;
    
    		m_start_index = rhs.m_start_index;
    	}
    
    	return *this;
    }
    As for using your assignment operator to implement the copy constructor, I didn't notice that. But still, you should presumably at least set m_array to 0 before the assignment. Otherwise it's an arbitrary value you're passing to delete in operator=.
    Code:
    template <typename T>
    SingleArray<T>::SingleArray(const SingleArray<T> &copy)
    {
    	m_array = 0;
    	*this = copy;
    }
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  6. #6
    Registered User
    Join Date
    Aug 2009
    Posts
    36
    Code:
    template <typename T>
    class SingleArray
    {
    public:
    	SingleArray();
    	SingleArray(int length, int start_index = 0);
    	SingleArray(const SingleArray<T> &copy);
    	~SingleArray();
    	SingleArray<T>& operator = (const SingleArray<T> &rhs);
    	T& operator [] (int index);
    	int getStartIndex();
    	void setStartIndex( int start_index );
    	int getLength();
    	void setLength( int length );
    
    private:
    	T * m_array;
    	int m_length;
    	int m_start_index;
    };
    
    //Default constructor
    template <typename T>
    SingleArray<T>::SingleArray() : m_array(0), m_length(0), m_start_index(0)
    {
    
    }
    
    //Two parameter constructor for setting length and the starting index
    template <typename T>
    SingleArray<T>::SingleArray(int length, int start_index = 0)
    {
    	m_length = length;
    	m_start_index = start_index;
    	m_array = new T[length];
    }
    
    //Copy Constructor
    template <typename T>
    SingleArray<T>::SingleArray(const SingleArray<T> &copy)
    {
    	m_array = 0;
    	*this = copy;
    }
    
    //Destructor
    template <typename T>
    SingleArray<T>::~SingleArray()
    {
    	delete [] m_array;
    	m_array = nullptr;
    	m_length = 0;
    	m_start_index = 0;
    }
    
    //Assignment Operator
    template <typename T>
    SingleArray<T> & SingleArray<T>::operator = (const SingleArray<T> &rhs)
    {
    	if(this != &rhs)
    	{
    		if(m_array)
    			delete [] m_array;
    
    		m_array = new T[rhs.m_length];
    
    		m_length = rhs.m_length;
    
    		for(int i = 0; i < m_length; ++i)
    		{
    			m_array[i] = rhs.m_array[i];
    		}
    
    
    		m_start_index = rhs.m_start_index;
    	}
    
    	return *this;
    }
    
    //Bracket operator
    template <typename T>
    T & SingleArray<T>:: operator [] (int index)
    {
    	index -= m_start_index;
    
    	if(index < 0)
    		throw Exception("Index lower than minimum");
    	else if(index >= m_length)
    		throw Exception("Index higher than maximum");
    
    	return m_array[index];
    }
    
    //Returns the start index
    template <typename T>
    int SingleArray<T>::getStartIndex()
    {
    	return m_start_index;
    }
    
    //Sets the start index to the passed in parameter
    template <typename T>
    void SingleArray<T>::setStartIndex( int start_index )
    {
    	m_start_index = start_index;
    }
    
    //Returns the length of the array
    template <typename T>
    int SingleArray<T>::getLength()
    {
    	return m_length;
    }
    
    //Sets the length of the array to the passed in parameter
    template <typename T>
    void SingleArray<T>::setLength( int length )
    {
    	T * temp = new T[length];
    
    	if(length < m_length)
    	{
    		for(int i = 0; i < length; ++i)
    		{
    			temp[i] = m_array[i];
    		}
    
    		delete [] m_array;
    
    		m_array = temp;
    
    		m_length = length;
    
    	}
    
    	else if(length > m_length)
    	{
    		
    		for(int i = 0; i < length; ++i)
    		{
    			temp[i] = m_array[i];
    		}
    
    		delete [] m_array;
    
    		m_array = temp;
    
    		m_length = length;
    	}
    }
    
    #endif

  7. #7
    Registered User
    Join Date
    Aug 2009
    Posts
    36
    Another problem I'm having is making this a const method.

    Code:
    template <typename T>
    Row<T> Array2D<T>::operator [] (const int index)
    {
    	if(index > m_row)
    		throw Exception("Index exceeds amount of rows");
    
    	return Row<T>(*this, index);
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Pointers and 2DArray
    By ganesh bala in forum C Programming
    Replies: 6
    Last Post: 02-18-2009, 04:28 PM
  2. 2Darray in 1Darray and sum elements
    By alzar in forum C Programming
    Replies: 13
    Last Post: 08-29-2007, 02:14 PM
  3. How do I display char 2darray in string form?
    By Mathsniper in forum C Programming
    Replies: 3
    Last Post: 12-06-2006, 01:52 PM