繁体   English   中英

2D阵列(矩阵)中的访问错误

[英]Bad Access Error in 2D-Array (Matricies)

我有一个小问题...我了解什么是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列working.get_element(i, j); 叫做。 变量列表显示我只是之前get_element()方法,这两个行和cols都设置为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中将其初始化为有意义的东西。

顺便说一句:为什么要这样做: Matrix working = *this; ?? 您可以简单地this->get_element(i, j); 而是不会调用整个对象的复制。 [1]

编辑:更新,因为您更新了答案。 您应该小心复制CTOR和operator=()语句。 很容易进行两次删除或类似的丑陋操作。

EDIT2:我认为问题是此行:

Matrix working = *this;

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

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

您的课堂违反了“ 三大原则”。 如果一个类具有析构函数,赋值运算符或复制构造函数之一,则很可能需要同时拥有这三个。

在您的情况下,您有一个析构函数,但没有赋值运算符或复制构造函数,并且在执行Matrix working = *this时,这将创建UB条件。

顺便说一下,您的代码还有另外两个问题

  1. 从评论看来,您认为new double[size]会将元素初始化为0,但事实并非如此。

  2. 从技术上讲,您的大多数代码都非常糟糕。 使用std::vector而不是指针和动态内存,可以轻松实现矩阵类(更少的代码)来正确实现。 当然,如果这只是一个练习,那么避免使用std::vector有意义的。

顺便说一句,如果您从未听说过“三大规则”,那么您很可能会尝试通过实验学习C ++,而不是通过阅读来学习。

使用C ++,这不是明智之举...如果1)主题高度逻辑,2)如果在错误时会被告知,则可以使用逻辑代替学习。

相反,C ++非常非常复杂,并且在某些地方(由于历史原因)也很不合逻辑,因此在某些地方,逻辑会误导您。

而且,当您在C ++中犯错时,通常不会收到错误消息,而是“未定义的行为”。 从根本上讲,通过实验很难学习C ++,因为即使错误的代码显然也可以工作。 编写看起来不错的代码也很容易,但是出于微妙的原因,这是完全错误的。

不仅要尝试,还应该抓住一本好书,然后翻阅封面...

您的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; ] [ 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; 或您希望它具有的任何默认值。

希望有所帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM