二维数组中的错误访问错误(矩阵)

时间:2011-10-05 07:48:05

标签: c++ c matrix exc-bad-access multidimensional-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个col。变量列表在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;
}

3 个答案:

答案 0 :(得分:1)

当您没有说明如何声明和初始化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;

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

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

答案 1 :(得分:1)

您的课程违反了“big three”规则。如果一个类有一个析构函数,赋值运算符或复制构造函数,那么很可能你需要全部三个。

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

顺便提一下,您的代码还存在其他两个问题

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

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

  3. 是有意义的

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

    使用C ++这不是一个聪明的举动...如果1)主题是高度逻辑的话,可以用逻辑代替学习,2)如果你弄错了就可以告诉你。

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

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

    而不仅仅是试验你应该grab a good book并阅读它以涵盖......

答案 2 :(得分:1)

您的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];
    }
}

你分配了内存,但是无论矩阵[0] [0]指向哪里,它都是未初始化的垃圾值。执行matrix[0][0] = 0;之类的操作或您希望它具有的任何默认值。

希望有所帮助。