2017-07-10 2 views
1

動的に割り当てられた配列のサイズを変更する方法を作成しようとしています。私は行と列を追加することができますが、元のサイズよりも小さくなるようにサイズを変更することはできません。C++で動的に割り当てられた配列を小さなサイズに変更する

template <class T> 
class Matrix 
{ 
public: 

// Constructors/Destructors 
Matrix(); 
Matrix(const int rows, const int cols); 
Matrix(const Matrix<T>& orig); 
~Matrix(); 

// Display 
void print() const; 

// Size modification 
void addRow(); 
void addCol(); 
void resize(const int rows, const int cols); 

// Element access 
T getCell(const int r, const int c) const; 

// Operator Access 
T& operator()(const int r, const int c)    { return mData[r * mCols + c]; } 
const T& operator()(const int r, const int c) const { return mData[r * mCols + c]; } 



// Getters/Setters 
int getRows() const; 
int getCols() const; 

private: 
    T* mData; 
    int mRows, mCols; 
}; 
//1 
template <class T> 
Matrix<T>::Matrix(void){ 
    mRows=0; 
    mCols=0; 
    mData=NULL; 
} 

//2 
template <class T> 
Matrix<T>::Matrix(const int rows, const int cols){ 
    if(rows!=0&&cols!=0) 
    { 
     mRows=rows; 
     mCols=cols; 
     int size = rows*cols; 
     mData = new T[size]; 
     for(int r=0;r<getRows();r++) 
     { 
      for(int c=0;c<getCols();c++) 
      { 
       mData[r * mCols + c]=0; 
      } 
     } 
    }else 
    { 
     mData=NULL; 
    } 
} 

//3 
template <class T> 
Matrix<T>::Matrix(const Matrix<T>& orig){ 
    if(orig.getRows()!=0&&orig.getCols()!=0) 
    { 
     T* temp = mData; 
     mRows=orig.getRows(); 
     mCols=orig.getCols(); 
     int size = mRows*mCols; 
     mData = new T[size]; 
     for(int r=0;r<getRows();r++) 
     { 
      for(int c=0;c<getCols();c++) 
      { 
       mData[r * mCols + c]=temp[r * mCols + c]; 
      } 
     } 
    }else 
    { 
     mData=NULL; 
    } 
} 

//4 
template <class T> 
Matrix<T>::~Matrix() 
{ 
    delete []mData; 
    mData=NULL; 
} 

//5 
template <class T> 
void Matrix<T>::print() const{ //to print the mData in a Matrix form 
    cout << endl; 
    int r=0,c=0,w=10; 
    for(r=0;r<getRows();r++){ 
     for(c=0;c<getCols();c++){ 
      cout << setw(w) << mData[r * mCols + c]; 
     } 
     cout << endl; 
    } 
} 

//6 
template <class T> 
void Matrix<T>::addRow(){ 
    T* temp = mData; 
    mRows=getRows()+1; 
    int size = mRows*mCols; 
    mData = new T[size]; 
    for(int r=0;r<getRows();r++) 
    { 
     for(int c=0;c<getCols();c++) 
     { 
      if(r==getRows()-1) 
      { 
       mData[r * mCols + c]=0; 
      }else 
      { 
       mData[r * mCols + c]=temp[r * mCols + c]; 
      } 

     } 
    } 
} 

//7 
template <class T> 
void Matrix<T>::addCol(){ 
    T* temp = mData; 
    mCols=getCols()+1; 
    int size = mRows*mCols; 
    mData = new T[size]; 
    for(int r=0;r<getRows();r++) 
    { 
     for(int c=0;c<getCols()-1;c++) 
     { 
       mData[r * mCols + c]=temp[r * (mCols-1) + c]; 
     } 
    } 
    int c=getCols()-1; 
    for(int r=0;r<getRows();r++) 
    { 
      mData[r * mCols + c]=0; 
    } 
} 

//8 
template <class T> 
void Matrix<T>::resize(const int rows, const int cols){ 


    if(rows>=getRows()) 
    { 
     while(rows!=getRows()) 
     { 
      addRow(); 
     } 
    } 

    if(cols>=getCols()) 
    { 
     while(cols!=getCols()) 
     { 
      addCol(); 
     } 
    } 


    T* temp = mData; 
    int tempCols = getCols(); 
    int size = rows*cols; 
    if(rows<getRows() || cols <getCols()) 
    { 
     delete []mData; 
     mData=NULL; 
     mData= new T[size]; 
     for(int r=0;r<getRows();r++) 
     { 
      for(int c=0;c<getCols();c++) 
      { 
        if(r<rows&&c<cols) 
        { 
         mData[r * mCols + c]=temp[r * (cols) + c]; 
        }else 
        { 
         mData[r * mCols + c]=NULL; 
        } 

      } 
     } 
    } 

} 


//9 
template <class T> 
T Matrix<T>:: getCell(const int r, const int c) const 
{ 
    T value; 
    if(r<getRows()&&c<getCols()&&r>=0&&c>=0) 
    { 
     value = mData[r * mCols + c] ; 
    }else 
    { 
     value = 0; 
    } 
    return(value); 
} 

//22 
template <class T> 
int Matrix<T>::getRows() const{ 
    return mRows; 
} 
//23 
template <class T> 
int Matrix<T>::getCols() const{ 
    return mCols; 
} 
#endif 

私が実装している他のすべての機能は完全に機能し、テストに役立つ移植を追加しました。

現在、マトリックスが3,4の場合、4,7に増やしたい場合、それは成功します。しかし、それを試して、それを2,2に切り捨てるならば、それは新しいサイズとループのためにそれが小さくなったはずであるにもかかわらず、3,4のままです。

ので、私の質問は、しかし、私は(3,4)マトリックスM1

1 2 3 4 
6 7 8 2 
3 2 1 1 

を持っている場合、私はm1.resize(2,7)を実行する場合、私は

1 2 3 4 0 0 0 
6 7 8 2 0 0 0 

を取得したいということです現在取得しています

3801280 3802496 2 3 4 0 0 
6  7  8 2 0 0 0 
0  0  0 0 0 0 0 
0  0  0 0 0 0 0 

私のサイズ変更の実装には何が問題になっていますか?

+0

あなたの質問は何ですか? "Something explodes"は質問ではありません –

+1

'std :: vector'を内部的に保持してみませんか? – Charles

+0

不幸にも、動的割り当て配列を使用してMatrix クラスを実装することで、抽象データ型(ADT)を理解することが課題です。 –

答えて

1

T* temp = mData;ディープコピーを実行しません。後でdelete []mData;のデータの温度を指しているときも消えています。後でtempを参照解除すると、未定義の動作がトリガされます。これは非常に残念です。なぜなら、時折、ランダムに、そして爆発するときに正しい結果を得ることがあるからです。 segfaultはより良いでしょう。

ここでは簡単な例を示します。ディープコピーを行わないラインdouble * temp = mData;も置いています。

#include <algorithm> 
#include <iostream> 

int main() 
{ 
    double * mData = new double[5]; 
    std::fill_n(mData, 5, 1); 

    double * temp = mData; // Wrong! No deep copy 
    //double * temp = new double[5]; 
    //std::copy(mData, mData+5, temp); 

    delete[] mData; 
    mData = new double[10]; 
    std::fill_n(mData, 10, 0); // fill with zeros 
    for (int i = 0; i < 5; ++i) 
    mData[i] = temp[i]; 

    for(int i = 0; i < 10; ++i) 
    std::cout << mData[i] << ' '; 
    std::cout << '\n'; 

    delete[] temp; 
    delete[] mData; 
} 

このプログラムの出力は、問題ありません。結局のところ、動作は未定義です。無効な操作を検出するには、メモリデバッガ(Linuxの場合はvalgrindなど)で手動でメモリ管理するプログラムを実行することをお勧めします。私が上記を実行する場合valgrind(いくつかの一般的なメッセージの中で)

==9998== Invalid read of size 8 
==9998== at 0x400908: main (in /home/henri/a.out) 
==9998== Address 0x5abfc80 is 0 bytes inside a block of size 40 free'd 
==9998== at 0x4C2F74B: operator delete[](void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==9998== by 0x4008C1: main (in /home/henri/a.out) 
==9998== Block was alloc'd at 
==9998== at 0x4C2E80F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==9998== by 0x40087A: main (in /home/henri/a.out) 
==9998== 
1 1 1 1 1 0 0 0 0 0 
==9998== Invalid free()/delete/delete[]/realloc() 
==9998== at 0x4C2F74B: operator delete[](void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==9998== by 0x4009A9: main (in /home/henri/a.out) 
==9998== Address 0x5abfc80 is 0 bytes inside a block of size 40 free'd 
==9998== at 0x4C2F74B: operator delete[](void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==9998== by 0x4008C1: main (in /home/henri/a.out) 
==9998== Block was alloc'd at 
==9998== at 0x4C2E80F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==9998== by 0x40087A: main (in /home/henri/a.out) 
関連する問題