【问题标题】:Bad Access Error in 2D-Array (Matricies)二维数组(矩阵)中的错误访问错误
【发布时间】:2011-10-05 07:48:05
【问题描述】:

我有一点问题...我了解 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;
};

请忽略 cmets 抱歉。这是构造函数/析构函数:

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 类构造函数(全部),以及您分配或释放其matrix 成员的任何其他位置。
  • 缺少(可能)与matrix 相关的复制分配运算符实现。 (Matrix &amp; operator=(const Matrix &amp;rhs);)
  • 你在这个函数中做了什么:Matrix &amp; operator=(const Matrix &amp;rhs);?

标签: c++ c matrix exc-bad-access multidimensional-array


【解决方案1】:

当您不说明如何声明和初始化matrix 元素时,我们不可能说。在你的 CTOR 中使用类似的东西应该没问题:

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

不要忘记在你的 CTOR 中将它初始化为有意义的东西。

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

编辑:更新,因为您更新了答案。您应该小心您的副本 CTOR 和 operator=() 语句。很容易进行双重删除或类似的丑陋。

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

Matrix working = *this;

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

我认为最好的办法是删除 Matrix working = *this; 行并遵守上面的提示: this-&gt;get_element(i, j);std::string Matrix::to_string() const

【讨论】:

  • 这就是我最初的想法,但我想我会改变它,看看它是否会改变任何东西。不幸的是,它并没有帮助,所以我将把它改回来以适应其余的代码。编辑:你在我的 CTOR 中是什么意思?抱歉,C++ 还是新手。
  • CTOR 是为构造函数拍摄的,即初始化对象的方法。您已经定义了其中 2 个:Matrix()Matrix(int, int)
  • 是的,我确实注意到有人感谢 Constantinius。我计划稍后修复的东西,但现在,我只想让其他一些东西正常工作。好的,所以使用我发布的 CTOR,我创建了具有正确行和列的矩阵。对吗?
  • 我把它换成了你说的,原来是这样,但谢谢你指出来。它仍然给出相同的错误,即使我通过将每个值初始化为 0 来执行下面的建议。编辑:这样做之后,它现在可以工作了。谢谢朋友,感谢您的帮助!
【解决方案2】:

您的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; 之类的操作或您希望它具有的任何默认值。

希望对您有所帮助。

【讨论】:

  • 这样做确实解决了我遇到的一个错误,谢谢伙计,不胜感激。这与另一个答案一起。
【解决方案3】:

您的班级违反了“big three”规则。如果一个类具有析构函数、赋值运算符或复制构造函数之一,那么很可能您需要同时拥有这三个。

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

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

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

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

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

对于 C++,这不是一个聪明的举动...如果 1) 主题高度合乎逻辑,2) 如果您在弄错时可以被告知,则可以使用逻辑代替学习。

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

此外,当您在 C++ 中出错时,通常不会收到错误消息,而是“未定义行为”。这基本上使得通过实验学习 C++ 变得非常非常困难,因为即使是错误的代码也可能显然起作用。编写看起来不错的代码也很容易,但由于一些微妙的原因却是完全错误的。

您应该grab a good book 并从头到尾阅读它,而不是仅仅进行试验......

【讨论】:

  • 嗯...以前从未听说过那个。赋值运算符和复制构造函数是什么意思?编辑:另外,是的,我知道它不会用值初始化它,这就是为什么我认为我应该在矩阵上调用 clear() 所以它是空的。我会使用向量,但它只是用于分配,所以我不太担心。
  • @Brandon:这是您的班级缺少的复制构造函数 (Matrix(Matrix const&amp;))。想一想:在您的分配代码 (operator=) 中,谁或什么为 matrix 分配了存储空间?分配了什么大小?
  • @Brandon:正如我之前所说,您的代码有很多问题(例如,当它们不正确时,它使用默认复制构造函数和默认赋值运算符,它不能正确处理异常,并且我的打赌,如果你实施分配,你的实施无论如何都是错误的)。关于使用向量,这将是更少的代码,同时正确的代码(你的代码不正确)。那么为什么你使用向量(如果这不仅仅是一个编程kata)?对于任何称职的 C++ 程序员std::vector 将是这个问题的第一个候选人......
猜你喜欢
  • 2018-04-11
  • 1970-01-01
  • 2017-10-11
  • 1970-01-01
  • 1970-01-01
  • 2023-04-05
  • 2019-08-03
  • 2017-02-07
  • 1970-01-01
相关资源
最近更新 更多