2D-Array(矩阵)访问错误



我有一个小问题…我知道EXC_BAD_ACCESS错误是什么,我通常知道如何修复它,但这一个已经让我完全填充。我把这些都放在一个类中,这里有一个方法:

double Matrix::get_element(int r, int c) const {
    //Retrieve the element at row r and column c
    //Should not modify the value stored in Matrix but return a double copy of the value
    double currentValue = matrix[r][c];
    return currentValue;
}
现在,我有另一段代码调用这个方法:
std::string Matrix::to_string() const {
    std::string result;
    double current;
    Matrix working = *this;
    std::ostringstream oss;
    oss << "[";
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            current = 0.0;
            current = working.get_element(i, j);
            oss << " " << current << " ";
        }
        oss << "; ";
    }
    oss << "]";
    result = oss.str();
    return result;
}

我知道工作对象在调用working.get_element(i, j);的地方有3行和3个颜色。变量列表显示,在get_element()方法之前,行和颜色都被设置为3。在该方法中,我能够得到get_element(0, 0)的值,但不能得到get_element(0, 1)的值。

我不明白为什么会这样…有人知道为什么或需要更多的我的代码来理解为什么这些方法被调用?

编辑:下面是头文件:

class Matrix {
private:
    //Any variables required
    int rows;
    int cols;
    double **matrix;
public:
    Matrix();   //Working M
    ~Matrix();  //Working M
    Matrix(int r, int c);   //Working M
    int getRows();
    int getCols();
    void set_element(int r, int c, double val); //Working M
    double get_element(int r, int c) const; //Working M
    void clear(); //Working M        
    bool is_empty(); //Working M         
    bool is_identity(); //Working M
    const Matrix transpose(); //Working M
    int minorMat(double **dest, const int row, const int col, int order); //Working M
    double get_determinent(); //Working M
    double higherDeterminents(int order); //Working M
    const Matrix operator+(const Matrix &rhs); //Working M       
    const Matrix operator-(const Matrix &rhs); //Working M    
    const Matrix operator*(const Matrix &rhs); 
    bool operator==(const Matrix &rhs); //NOT assessed
    const Matrix operator*(const double &rhs);        
    const Matrix operator/(const double &rhs);
    Matrix & operator=(const Matrix &rhs);
    std::string to_string() const;
};

请忽略注释,对不起。这是构造函数/析构函数:

Matrix::Matrix() {
    //Basic Constructor
    rows = 1;
    cols = 1;
    matrix = new double*[rows];
    for (int i = 0; i < rows; ++i) {
        matrix[i] = new double[cols];
    }
}
Matrix::~Matrix() {
    //Basic Deconstructor
    for (int i = 0; i < rows; ++i) {
        delete[] matrix[i];
    }
    delete[] matrix;
    rows = NULL;
    cols = NULL;
    matrix = NULL;
}
Matrix::Matrix(int r, int c) {
    //Empty matrix (all 0's) with r rows and c columns, if they are -ve, set to 1
    rows = r;
    cols = c;
    if (cols < 0)
        cols = 1;
    if (rows < 0)
        rows = 1;
    matrix = NULL;
    matrix = new double*[rows];
    for (int i = 0; i < rows; i++) {
        matrix[i] = new double[cols];
    }
}

EDIT2:

Matrix & Matrix::operator=(const Matrix &rhs) {
    //rhs is matrix to be copied
    //rhs compied into Matrix called on
    double toCopy;
    for (int i = 0; i < rhs.rows; i++) {
        for (int j = 0; j < rhs.cols; j++) {
            toCopy = rhs.get_element(i, j);
            this->set_element(i, j, toCopy);
        }
    }
    return *this;
}

如果您没有说明如何声明和初始化matrix元素,我们就不可能说出来。在您的CTOR中使用类似的内容应该没问题:

class Matrix {
   float matrix[3][3];
   ...
}

别忘了在你的CTOR中把它初始化为有意义的东西。

Btw:你为什么这样做:Matrix working = *this; ??您可以简单地使用this->get_element(i, j);,这样就不会调用对整个对象的复制。[1]

编辑:更新,因为你更新了你的答案。您应该小心使用您的复制ctor和operator=()语句。很容易进行双重删除或诸如此类的丑陋操作。

EDIT2:我认为问题出在这一行:

Matrix working = *this;

您正在创建this对象的新副本working。但是working初始化时只有1列和1行(如标准CTOR中定义的那样)。我不确定您是否在调用set_elementget_element时检查边界,所以我猜您正在编写数组的边界。

我认为最好的主意是删除Matrix working = *this;行,并坚持我上面的提示:this->get_element(i, j); in std::string Matrix::to_string() const .

您的Matrix(int r, int c)matrix分配内存,但保留其指向的值未初始化。在构造函数中添加如下内容:

for (int i = 0; i < r; i++) {
        for (int j = 0; j < c; j++) {
            this->set_element(i, j, 0);
        }
    }

这样做:

int main()
{
    Matrix m(3,3);
    std::cout << m.to_string();
}
输出:

[ 0 0 0; 0 0 0; 0 0 0; ] .

默认构造函数也一样:

Matrix::Matrix() {
    //Basic Constructor
    rows = 1;
    cols = 1;
    matrix = new double*[rows];
    for (int i = 0; i < rows; ++i) {
        matrix[i] = new double[cols];
    }
}

您分配了内存,但是无论matrix[0][0]指向哪里,它都是未初始化的垃圾值。如matrix[0][0] = 0;或任何你想要的默认值。

希望对你有帮助。

你的课违反了"三巨头"规则。如果一个类有析构函数、赋值操作符或复制构造函数中的一个,那么很可能需要同时拥有这三个。

在您的例子中,您有析构函数,但没有赋值操作符或复制构造函数,这将在执行Matrix working = *this时创建UB条件。

顺便说一下,你的代码还有两个问题
  1. 从评论看来,您认为new double[size]将初始化元素为0,这是不正确的。

  2. 你的大部分代码在技术上是非常糟糕的。使用std::vector而不是指针和动态内存来正确实现矩阵类会容易得多(代码更少)。当然,如果这只是一个练习,那么避免使用std::vector是有意义的。

顺便说一下,如果你从来没有听说过"三大"规则,那么你很可能是在尝试通过实验来学习c++,而不是通过阅读。

对于c++,这不是一个明智的举动…逻辑可以用来代替学习,如果1)话题是高度逻辑的,2)如果你能告诉你什么时候你错了。

相反,c++非常非常复杂,在一些地方也非常不合逻辑(由于历史原因),所以有些部分逻辑会简单地误导你。

此外,当你在c++中犯错误时,你通常不会得到一个错误消息,而是"未定义的行为"。这基本上使得通过实验学习c++变得非常非常困难,因为即使是错误的代码也可能显然有效。也很容易写出看起来不错的代码,但实际上却因为一些微妙的原因而完全错误。

不要只是做实验,你应该找一本好书,从头到尾读一遍…

相关内容

  • 没有找到相关文章

最新更新