二维数组(矩阵)中的错误访问错误
我有一点问题...我了解 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);
被调用。变量列表显示在 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];
}
}
编辑2:
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;
}
I have a little bit of a problem... I understand what a EXC_BAD_ACCESS error is and I generally know how to fix it but this one has got me completely stuffed. I have this all within a class, here is one method:
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;
}
Now, I have another piece of my code that calls this method:
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;
}
I know that the working object has 3 rows and 3 cols at the point where working.get_element(i, j);
is called. The variable list shows me just before the get_element()
method, that both rows and cols are set to 3. In the method, I'm able to get the value at get_element(0, 0)
but not get_element(0, 1)
.
I can't see why this is the case... Anyone know why or require more of my code to understand why these methods are being called?
EDIT:
Here is the header file:
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;
};
Do ignore the comments sorry. And this is the constructors/destructors:
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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果您不说明如何声明和初始化矩阵元素,我们就无法判断。在 CTOR 中使用类似的东西应该没问题:
不要忘记在 CTOR 中将其初始化为有意义的东西。
顺便说一句:为什么要这样做:
Matrixworking = *this;
??您可以简单地使用this->get_element(i, j);
来代替,这不会调用整个对象的复制。[1]
编辑:更新您的答案。您应该小心复制 CTOR 和
operator=()
语句。很容易进行双重删除或类似的丑陋的事情。EDIT2:我认为问题在于这一行:
您正在创建
this
对象的新副本working
。但是working
仅使用 1 列和 1 行进行初始化(如标准 CTOR 中所定义)。我不确定您在调用set_element
或get_element
时是否检查边界,所以我猜您正在写入数组的边界。我认为最好的想法是删除 Matrixworking = *this; 行并遵循上面的提示:
std::string Matrix::to_string() const 中的
this->get_element(i, j);
。It is impossible for us to say when you do not state how you declare and initialize the
matrix
element. Using something like that in your CTOR should be fine:Don't forget to initialize it in your CTOR to something that makes sense.
Btw: why do you do this:
Matrix working = *this;
?? You could simplythis->get_element(i, j);
instead, which would not invoke copying of your whole object.[1]
EDIT: Update since you updated your answer. You should be careful with your copy CTORs and
operator=()
statements. It is easily possible to make double deletes or something ugly like that.EDIT2: I think the problem is this line:
You are creating a new copy
working
of yourthis
object. Butworking
gets initialized with only 1 column and 1 row (as defined in your standard CTOR). I'm not sure if you are checking the bounds when callingset_element
orget_element
so I guess you are writing over the bounds of your arrays.I think the best idea is to just remove the line
Matrix working = *this;
and to adhere to my tip in above:this->get_element(i, j);
instd::string Matrix::to_string() const
.您的 Matrix(int r, int c) 为矩阵分配内存,但保留其指向的值未初始化。在构造函数中添加类似的内容:
这样做:
输出:
[ 0 0 0; 0 0 0; 0 0 0; ]
。默认构造函数中的情况相同:
您分配了内存,但无论 Matrix[0][0] 指向何处,它都是未初始化的垃圾值。执行诸如
matrix[0][0] = 0;
之类的操作或您希望其具有的任何默认值。希望有帮助。
Your
Matrix(int r, int c)
allocates memory formatrix
, but leaves the values it points to uninitialized. Add something like this to the constructor:Doing like this:
Output:
[ 0 0 0; 0 0 0; 0 0 0; ]
.Same thing in the default constructor:
You allocated memory, but wherever matrix[0][0] points to, it's uninitialized garbage value. Do something like
matrix[0][0] = 0;
or whatever default value you want it to have.Hope that helps.
您的班级违反了“三巨头”规则。如果一个类具有析构函数、赋值运算符或复制构造函数之一,那么您很可能需要同时拥有这三个函数。
在您的情况下,您有一个析构函数,但没有赋值运算符或复制构造函数,当您执行 Matrixworking = *this 时,这将创建一个 UB 条件。
顺便说一句,您的代码还有另外两个问题
从评论中看来,您认为
new double[size]
会将元素初始化为 0,但事实并非如此。您的大部分代码在技术上都非常糟糕。使用 std::vector 而不是指针和动态内存,您的矩阵类将更容易(更少的代码)正确实现。当然,如果这只是一个练习,那么避免使用 std::vector 是有意义的。
顺便说一句,如果您从未听说过“三大”规则,那么您很可能正在尝试通过实验而不是通过阅读来学习 C++。
对于 C++,这不是明智之举……如果 1)该主题具有高度逻辑性,2)如果您可以在犯错时被告知,则可以使用逻辑来代替学习。
相反,C++ 非常非常复杂,并且在某些地方也非常不合逻辑(由于历史原因),因此有些部分的逻辑会简单地误导您。
此外,当您在 C++ 中犯错误时,您通常不会收到错误消息,而是收到“未定义的行为”。这基本上使得通过实验学习 C++ 变得非常困难,因为即使是错误的代码也可能显然工作。编写看起来不错但实际上由于微妙原因而完全错误的代码也很容易。
你不应该只是尝试,而应该拿一本好书并阅读它的封面覆盖...
Your class is violating the "big three" rule. If a class has one of a destructor, assignment operator or copy constructor then it most probably you need to have all three.
In your case you have a destructor, but no assignment operator or copy constructor, and this is going to create an UB condition when you do
Matrix working = *this
.By the way there are two other problems with your code
From the comment seems that you think that
new double[size]
will initialize the elements to 0 and this is not true.Most of your code is technically very bad. Your matrix class would be much easier (less code) to implement correctly using
std::vector
instead of pointers and dynamic memory. Of course if this is just an exercise then it make sense to avoid usingstd::vector
.By the way if you never heard about the "big three" rule chances are that you're trying to learn C++ with experimentation instead that by reading.
With C++ this is not a smart move... logic can be used as substitute for study if 1) the topic is highly logical, 2) if you can be told when you get it wrong.
Instead C++ is very very complex and in a few place is also quite illogical (for historical reasons) so there are parts in which logic will simply misguide you.
Moreover when you make a mistake in C++ you don't get in general an error message, but "Undefined Behavior". This basically makes very very hard to learn C++ with experimentation because even wrong code may apparently work. It is also very easy to write code that looks good and that is instead quite wrong for subtle reasons.
Instead of just experimenting you should grab a good book and read it cover to cover...