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;
}
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:
class Matrix {
float matrix[3][3];
...
}
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 simply this->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:
Matrix working = *this;
You are creating a new copy working of your this object. But working 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 calling set_element or get_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); in std::string Matrix::to_string() const.
Your Matrix(int r, int c) allocates memory for matrix, but leaves the values it points to uninitialized. Add something like this to the constructor:
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
this->set_element(i, j, 0);
}
}
Doing like this:
int main()
{
Matrix m(3,3);
std::cout << m.to_string();
}
Output:
[ 0 0 0; 0 0 0; 0 0 0; ].
Same thing in the default constructor:
Matrix::Matrix() {
//Basic Constructor
rows = 1;
cols = 1;
matrix = new double*[rows];
for (int i = 0; i < rows; ++i) {
matrix[i] = new double[cols];
}
}
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.
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 using std::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...
Related
I'm currently working on a bigger project which involves implementing a linear algebra calculator. I have decided to not use any other already-existing libraries which might help me implement it as I thought it would be too easy.
I first started to code the Matrix class, which now looks like this:
class Matrix{
private:
int rows; // no. rows
int columns; // no. columns
double** matVal; //values of the matrix
char name; //only used when printing it out or by outside programs.
public:
//constructors and destructor
Matrix();
Matrix(int r,int c,char _name);
~Matrix();
//basic get functions for private access
int getNrRows();
int getNrCols();
char getName();
double getVal(int row,int col);
//basic set functions for private variables
void setVal(int row,int col,double value);
void setName(char _name);
//basic matrix operations
Matrix operator=(Matrix M);
Matrix operator+(Matrix M);
Matrix operator-(Matrix M);
Matrix operator*(Matrix M);
//Printing out the matrix
void Print();
};
At first it went smoothly, but then I stumbled into a fatal bug which wont allow me to progress further. For more information, here are my functions ( + some code to try to figure out what's wrong) and what I executed in main():
#define cout std::cout
Matrix::Matrix(){
rows = 0;
columns = 0;
matVal = nullptr;
}
Matrix::Matrix(int r,int c,char _name){
rows = r;
columns = c;
name = _name;
matVal = new double*[r];
for(int i = 0; i < r; i++){
matVal[i] = new double[c];
}
for(int i = 0; i < r; i++){
for(int j = 0; j < c; j++){
matVal[i][j] = 0;
}
}
}
Matrix::~Matrix(){
for (int i = 0; i < rows; i++)
delete[] matVal[i];
delete[] matVal;
}
int Matrix::getNrRows(){
return rows;
}
int Matrix::getNrCols(){
return columns;
}
char Matrix::getName(){
return name;
}
double Matrix::getVal(int row, int col){
return matVal[row-1][col-1];
}
void Matrix::setVal(int row,int col,double value){
matVal[row-1][col-1] = value;
}
void Matrix::setName(char _name){
name = _name;
}
Matrix Matrix::operator=(Matrix M){
for (int i = 0; i < rows; i++)
delete[] matVal[i];
delete[] matVal;
rows = M.rows;
columns = M.columns;
matVal = new double*[rows];
for(int i = 0; i < rows; i++){
matVal[i] = new double[M.columns];
}
for(int i = 0; i < M.rows; i++){
for(int j = 0; j < M.columns; j++){
matVal[i][j] = M.matVal[i][j];
cout<<matVal[i][j]<<' ';
}
cout<<'\n';
}
cout<<this<<std::endl;
return *this;
}
Matrix Matrix::operator+(Matrix M){
Matrix Rez;
Rez.rows = rows;
Rez.columns = columns;
for(int i = 0; i < rows; i++){
for(int j = 0; j < columns; j++){
Rez.matVal[i][j] = matVal[i][j] + M.matVal[i][j];
}
}
return Rez;
}
void Matrix::Print(){
cout<<'\n';
cout<<name<<": "<<"\n";
for(int i = 0; i < rows; i++){
for(int j = 0; j < columns; j++){
cout<<matVal[i][j]<<' ';
}
cout<<'\n';
}
cout<<'\n';
return;
}
Main:
Matrix M(4,3,'A');
M.setVal(1,1,2);
M.setVal(1,3,-1.1);
M.Print();
Matrix A(4,3,'B');
A.setVal(3,2,5);
A.Print();
Matrix C(4,3,'C');
C = A;
cout<<C.getVal(3,2)<<'\n';
cout<<C.getNrCols()<<" "<<C.getNrRows()<<endl;
C.Print();
cout<<"S"<<endl;
Printing the first 2 matrices works fine, when I print each element of C in the operator= function after I assigned it the proper value, again, it works fine, but when I use the Print() function on C it crashes. Here is the console output for the code above:
A:
2 0 -1.1
0 0 0
0 0 0
0 0 0
B:
0 0 0
0 0 0
0 5 0
0 0 0
0 0 0
0 0 0
0 5 0
0 0 0
0x69fed0
5
3 4
C:
At first I had absolutely no idea why it did that, but then I printed the pointer to each variable instead(it printed it all and returned 0 this time):
A:
0x850e38 0x850e40 0x850e48
0x851318 0x851320 0x851328
0x851338 0x851340 0x851348
0x851358 0x851360 0x851368
B:
0x851390 0x851398 0x8513a0
0x8513b0 0x8513b8 0x8513c0
0x8513d0 0x8513d8 0x8513e0
0x855b08 0x855b10 0x855b18
0x855b40 0x855b48 0x855b50
0x855b60 0x855b68 0x855b70
0x855b80 0x855b88 0x855b90
0x855ba0 0x855ba8 0x855bb0
0x69fed0
5
3 4
C:
0 0x8 0x10
0 0x8 0x10
0 0x8 0x10
0 0x8 0x10
S
Now I think that there is a problem with the Print function (because otherwise why would I be able to get the 5 printed out in main?). I still don't know exactly what is happening so I ask for your help. I'm sorry if this is a rookie mistake, I'm still quite inexperienced.
I also forgot to add that the class and class functions are in separate files (header and cpp), although I don't know how this could affect things.
The signature Matrix operator=(Matrix&); proposed in another answer it totally wrong. The correct signature should be
Matrix& operator=(const Matrix&);
or
void operator=(const Matrix&);
if you don't need chaining of assignments (a = b = c).
The bare minimum that you have to implement: copy constructor, copy assignment, and destructor. For a matrix class it is also reasonable to implement move operations. This is known as the rule of zero/three/five (it is five in our case):
If a class requires no user-defined constructors, no user-defined assignment operators and no user-defined destructor, don't define them; if a class requires a user-defined destructor, a user-defined copy (and move) constructor, or a user-defined copy (and move) assignment operator, it almost certainly requires all three (five).
Let's assume that matrix internally is represented as a 1D array. This approach avoids unnecessary indirection for matrix element access and simplifies code.
class Matrix {
public:
Matrix(const Matrix&);
Matrix(Matrix&&);
Matrix& operator=(const Matrix&);
Matrix& operator=(Matrix&&);
~Matrix();
private:
double* data_ = nullptr;
std::ptrdiff_t rows_ = 0;
std::ptrdiff_t cols_ = 0;
};
Copy operations should be deep, i.e. they should copy data, not just underlying pointer. Let's start with a copy constructor. It should allocate storage, then copy data from other to this storage:
Matrix(const Matrix& other)
: rows_(other.rows_), cols_(other.cols_) {
const auto n = other.rows_ * other.cols_;
data_ = new double[n];
std::copy(other.data_, other.data_ + n, data_);
}
Now let's implement swap:
void swap(Matrix& other) {
std::swap(rows_, other.rows_);
std::swap(cols_, other.cols_);
std::swap(data_, other.data_);
}
This function is very useful, because it allows us to implement move constructor, copy assignment and move assignment with almost no code:
Matrix(Matrix&& other) {
swap(other);
}
Matrix& operator=(const Matrix& other) {
Matrix(other).swap(*this);
return *this;
}
Matrix& operator=(Matrix&& other) {
Matrix(std::move(other)).swap(*this);
return *this;
}
With such canonical implementations you can be sure that these functions are implemented correctly (including self-assignment handling) once you have correct implementations of copy constructor and swap. Appreciate the elegance of the copy-and-swap idiom.
Now let's talk about operator+. Take a look at this implementation:
Matrix operator+(Matrix other) const {
assert(rows_ == other.rows_);
assert(cols_ == other.cols_);
const auto n = rows_ * cols_;
for (std::ptrdiff_t i = 0; i < n; ++i)
other.data_[i] += data_[i];
return other;
}
Here we take the argument by value and get a (deep) copy of it. Then we add this->data_ to the copy and return that copy. There is no need to introduce another local Matrix variable.
Complete demo
you can change the operator= function to this form:
Matrix operator=(Matrix &M);
and in definition you should change its return to:
return M;
i checked this and worked.
in operator+(and *) consider this note too.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I am working on my own matrix class in Qt. I know there is a QGenericMatrix class template, but I need to set the size at runtime, which is not possible with this one. Apart from that I see this as a nice project to revive my linear algebra knowledge by implementing this.
However, I have already been able to define the * operator (multiplication) as follows:
MyMatrix.h
public:
MyMatrix(int rows, int cols, double initValues=0.0); // constructor to create NxM matrix with N=col, M=rows
MyMatrix& operator*(double value); // multiply matrix with a double
private:
int rows;
int cols;
double **mat;
void initMatrix(int rows=1, int cols=1); // initialise the matrix, if no rows,cols are given it creates a "1x1 matrix"
MyMatrix.cpp
// constructor
MyMatrix::MyMatrix(int rows, int cols, double initValues)
{
initMatrix(rows, cols);
for (int i = 0; i < this->rows; ++i) {
for (int j = 0; j < this->cols; ++j) {
this->mat[i][j] = initValues;
}
}
}
// multiply each element in matrix by value
MyMatrix& MyMatrix::operator*(double value) {
for (int i = 0; i < this->rows; ++i) {
for (int j = 0; j < this->cols; ++j) {
this->mat[i][j] = this->mat[i][j] * value;
}
}
return *this;
}
// initialise all matrix cells
void MyMatrix::initMatrix(int rows, int cols)
{
this->rows = rows; // assign argument to member variable rows
this->cols = cols; // assign argument to member variable cols
this->mat = new double*[this->rows]; // initialise mat with list of doubles ptrs with length rows
for (int i = 0; i < this->rows; ++i) { // iterate over each row-element
this->mat[i] = new double[this->cols]; // initialise each rows-element with list of doubles with length cols
}
}
main.cpp
int rows = 2;
int cols = 3;
MyMatrix mat1(rows, cols, 1.0); // creates matrix with all elements 1.0
mat1 = mat1 * 3.0;
Note I extracted only the relevant parts, the class has grown already, so I guess posting the all three files completely would be more confusing.
So far so good. The above seems to do what it should.
Now, I want to be able to directly access each element in the matrix. Similar to how one can access elements in a QVector, like so:
Read an element:
double temp = mat1[2][2] // read the element in row=2, column=2
Write to an element:
double temp = 17;
mat1[2][2] = temp // set value of element in row=2, column=2 to given double temp (here 17).
But I do not know how to define this [][] operator. I tried the following definition analog to the multiplication with a double, and because I need to give the row and column. I thought I try:
MyMatrix.h
MyMatrix& operator[int c][int r](double value); // write
MyMatrix& operator[int c][int r](); // read
The implementation to overwrite/read the element in row r and column c which I have in mind should look like this:
MyMatrix.cpp
// write to element
MyMatrix& MyMatrix::operator[int r][int c](double value) {
this->mat[r][c] = value;
return *this;
}
// read to element
double& MyMatrix::operator[int r][int c]() {
return this->mat[r][c];
}
But that does not do the Trick.
Btw: Even before compiling QtCreator says:
/path/MyMatrixClass/mymatrix.cpp:60: error: expected ']'
/path/MyMatrixClass/mymatrix.cpp:60: to match this '['
/path/MyMatrixClass/mymatrix.cpp:60: error: expected '(' for function-style cast or type construction
/path/MyMatrixClass/mymatrix.cpp:61: error: use of undeclared identifier 'r'
/path/MyMatrixClass/mymatrix.cpp:61: error: use of undeclared identifier 'c'
I tried already searching a for these errors, but so far I could not find anything giving me a clue to what I want to achieve.
So, perhaps someone can give me a link on where to look for an example or some advice on how I can achieve what I want.
PS: Later I also want to be able to extract a certain row, or certain column, but I guess (=hope) that should be straight forward once I know how to handle the [][] operator the right way.
This is the first time I am really defining my own operators for a class. And I think I got the general idea from the * operator. (I have also + and - operators already working). However, until now I used Qt mostly for GUI building, simple data handling with QVectors, plotting spectra and alike. So, I guess I am just missing some basic Qt/c++ syntax.
You can have the matrix use the operator() with as many parameters as you like. Squared brackets won't work.
double const& operator()(size_t rowIndex, size_t colIndex) const;
double& operator()(size_t rowIndex, size_t colIndex);
Then, you can use your matrix class like this
Matrix M(n, n);
for (size_t i = 0; i < n; ++i) {
M(i, i) = 1.0;
}
return M;
There is no [][] operator. If you use the [] on two-diminsional array, you will get another pointer. Finally, you apply [] operator a second time on pointer returned from the first [] operator. Can use this little hack below. But this wont solve your problems on the long run:
#include <iostream>
#include <vector>
class Matrix
{
int rows, cols;
double**data;
public:
Matrix(int rows, int cols, double init)
:rows(rows),cols(cols),data(new double*[rows])
{
for (int i = 0; i < this->rows; ++i) {
data[i] = new double[cols];
for (int j = 0; j < this->cols; ++j) {
this->data[i][j] = init;
}
}
}
const double *operator[](int row)const
{
return data[row];
}
const double& operator[](const std::pair<int,int>& key)const
{
return data[key.first][key.second];
}
double& operator[](const std::pair<int, int>& key)
{
// validate the key
return data[key.first][key.second];
}
double *operator[](int row)
{
return data[row];
}
};
int main()
{
Matrix m(3, 4, 0);
m[2][1] = 3;
std::cout << m[std::make_pair(2, 1)];
// C++17 also allows:
// std::cout << m[{2, 1}];
std::cin.get();
}
Outputs: 3
I added a std::pair approach, m[{2, 1}] looks like syntax suggar.
I cannot recommend the pointer solution.
You dont have to reinvent the wheel neither. Take a look at newmath 11: http://www.robertnz.net/nm11.htm
So, since the QVector class is already quite powerful, and I assume it shall later more easy to deal with vector operations on my matrix class, I did now the following
My matrix class now the following content:
MyMatrix.h
Public:
MyMatrix(int rows, int cols, double initValues=0.0); // constructor
QVector<double> operator[](int idx);
Private:
QVector<QVector<double>> *mat;
My implementation of the operator is then as follows:
MyMatrix.cpp
// constructor
MyMatrix::MyMatrix(int rows, int cols, double initValues)
{
QVector<double> tmpRow(cols, initValues);
this->mat = new QVector<QVector<double>>(rows, tmpRow);
}
// operator definition
QVector<double> MyMatrix::operator[](int idx) {
QVector<double> temp = this->mat[0][idx];
return temp;
}
I dont really understand though why the [0] is needed. Because mat is a QVector< QVector < double >>, so the first should give a QVector< double >, but for some reason it behaves not as I would expect, i.e. this->mat[idx] should return the QVector< double >.
Anyway, with the above I can now use it like this:
main.cpp
qDebug() << mat1[0]; // prints the QVector in row=0
qDebug() << mat1[1]; // prints the QVector in row=1
qDebug() << mat1[1][1]; // prints element in row=1 and column=1
qDebug() << mat1[1][2]; // prints element in row=1 and column=2
This then prints:
QVector(1, 1, 1)
QVector(1, 1, 1)
1
1
So that is not yet really finished, but I think I am now heading in the right direction.
Btw, #PaulMcKenzie shared a link saying that () is better than []. I implemented the operator for () and []. Both worked, just with the exception, that the syntax is with () slightly different; the usage is then:
main.cpp
qDebug() << mat1(0); // prints the QVector in row=0
qDebug() << mat1(1)[1]; // prints element in row=1 and column=1
Which looks odd. So I think in my case the [] looks better, and I can directly use the QVector as normal with the [].
I will look into this in more detail tomorrow to see if I can now achieve what I want. Either way, so far thank for all the input. Any comment is greatly appreciated.
I'm trying to add two matrices using multidimensional arrays and overloading the addition operator '+' and the assignment operator '=' however, garbage data is passed to my overloaded assignment operator function.
I've been reading things about the Copy and Swap Idioms and so on but I can't seem to find a solution to my problem, and I'd prefer to use + and = separately, rather than '+=' which I've seen some people do, because I will use other arithmetic for matrices, but I want to get this solved first.
Here is my header:
#ifndef Matrix_h
#define Matrix_h
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <utility>
class Matrix
{
private:
int row;
int column;
double ** elements;
public:
Matrix();
Matrix(int r, int c); //constructor
Matrix(const Matrix& src); //copy constructor
~Matrix(); //destructor
Matrix& operator=(const Matrix& right); // assignment operator
int getRow() const;
int getColumn() const;
void setElement(int r, int c, double data);
double getElement(int r, int c) const;
Matrix& operator+(const Matrix& right); // calculates the sum of two matrices
};
#endif
Here are my function definitions:
#include <string.h>
#include "matrix.h"
using namespace std;
Matrix::Matrix(int r, int c){ //defines the constructor to create a new matrix
row = r;
column = c;
elements = new double*[row];
for (int i=0; i<row; i++){
elements[i] = new double[column];
}
for (int i=0; i<row; i++){
for (int j=0; j<column; j++){
elements[i][j] = 0;
}
}
}
Matrix::Matrix(const Matrix& src){ //defines the copying constructor
row = src.row;
column = src.column;
elements = new double*[row];
for (int i=0; i<row; i++){
elements[i] = new double[column];
}
for (int i=0; i<row; i++){
for (int j=0; j<column; j++){
elements[i][j] = src.elements[i][j];
}
}
}
Matrix::~Matrix() { //defines the destructor
for (int i=0; i<row; i++){
delete[] elements[i];
}
delete[] elements;
};
void Matrix::setElement(int r, int c, double data) {
elements[r][c] = data;
};
double Matrix::getElement(int r, int c) const {
return elements[r][c];
}
int Matrix::getColumn() const {
return column;
}
int Matrix::getRow() const {
return row;
}
Matrix& Matrix::operator =(const Matrix& right) {
if(this->elements != right.elements && column==right.column && row==right.row)
{
memcpy ( &this->elements, &right.elements, sizeof(this->elements) );
}
return *this;
}
Matrix& Matrix::operator +(const Matrix& right) {
// first, make sure matrices can be added. if not, return original matrix
if (this->row != right.row || this->column != right.column){
cout << "Matrix sizes do not match.";
return (*this);
}
Matrix sum(row, column);
for (int i=0; i<this->row; i++){
for (int j=0; j<this->column; j++){
sum.elements[i][j] = this->elements[i][j] + right.elements[i][j];
}
}
return sum;
}
My main simply creates matrixA with a 4x4 matrix of 1s and matrixB with a 4x4 matrix of 2s and adds them where the sum = matrixC which should result in a 4x4 matrix of 3s. However, this is my result:
matrixA
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
matrixB
2 2 2 2
2 2 2 2
2 2 2 2
2 2 2 2
matrixC before addition
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
matrixC after addition
1.0147e-316 3 3 3
1.0147e-316 3 3 3
1.0147e-316 3 3 3
1.0147e-316 3 3 3
When I test it to see what elements are passed to 'right' in the '=' function I noticed similar data as the first column of matrixC. I believe I'm not understanding the passing of references involved here fully so I'd like some help on that.
Your assignment operator is broken (and logically flawed).
It's logically flawed because an assignment like m1 = m2 should result in m1 == m2, no matter what the previous state of m1 was. Your implementation only attempts to copy when they have the same size. You should resize the matrix on the left side of the assignment.
Your operator also isn't using memcpy correctly. memcpy(dest, src, count) will copy contiguous data from the address src to the address dest. The addresses you're providing are the addresses of pointers to pointers to int, not pointers to a contiguous block of ints. There are two levels of indirection here that memcpy simply has no clue about. Also, sizeof(this->elements) is sizeof(int**), which will be a constant of probably 4 or 8 bytes, which should also seem wrong. To fix this, I would just use a plain old set of for loops.
Matrix& Matrix::operator=(const Matrix& other){
// attempt to acquire memory before modifying (for exception safety)
int** temp = new int*[other.row];
for (int i = 0; i < other.row; ++i){
temp[i] = new int[other.col];
}
// cleanup
for (int i = 0; i < row; ++i){
delete[] elements[i];
}
delete[] elements;
// copy data
elements = temp;
row = other.row;
col = other.col;
for (int i = 0; i < row; ++i){
for (int j = 0; j < col; ++j){
elements[i][j] = other.elements[i][j];
}
}
return *this
}
Another important note: Your operator+ returns a reference to a local variable. This is very bad, but C++ doesn't protect you from it. You should just return sum by value.
In modern C++, we generally prefer to use safer alternatives to manual memory management like std::vector<std::vector<int>>, which go a long way to seamlessly enforce correct usage and to save you from yourself.
Hmm, my CLang compiler warns me that operator +(const Matrix& right) return a reference to a temporary which is Undefined Behaviour.
You must return a plain object and not a reference:
Matrix operator=(const Matrix& right); // assignment operator
Matrix& Matrix::operator +(const Matrix& right) {
// ...
Matrix sum(row, column);
// ...
return sum;
}
You're returning a reference to an automatic local (sum).
You can see the canonical forms of the arithmetic operators here, and addition should look like
Matrix Matrix::operator+(const Matrix &b) const;
There are various other issues, some mentioned in other answers, but the only thing your current operator+ reliably produces is Undefined Behaviour.
A hint: if you store the matrix as one array double m[rows * columns] the implementation is going to be much simpler.
Indexing [row][column] is m[row * columns + column].
Summing is just summing two arrays element-wise (vector sum essentially).
I am trying to write a function to extract a slice from a given matrix, where the input is 1D and the slice can be 1D or 2D.
I am trying to use the push_back function for this purpose but for some reasons the push_back does not work.
I receive an error in my line OutPut.push_back(DumyValue);
Can anyone help me why I am receiving this error?
Also, it would be appreciated if you can tell me how to solve this issue.
Also, if the first part becomes clear, can anyone tell me how I should use the push_back for inserting an integer in a specific location so I can use it for extracting a 2D slice?
If you remove the line OutPut.push_back(DumyValue); the code should work.
#include<iostream>
#include<vector>
using namespace std;
int MatrixSlice(vector<vector<int>> Input, int Row1, int Row2, int Col1, int Col2) {
//define the slice size, if it is iD or 2D
if (abs(Row1-Row2)>1 && abs(Col1-Col2)>1){
vector<vector<int>> OutPut;
}else{
vector<int> OutPut;
}
int i2;
int j2;
for (int i = Row1; i <= Row2; i++) {
i2=0;
for (int j = Col1; j <= Col2; j++) {
int DumyValue=Input[i][j];
OutPut.push_back(DumyValue);
i2++;
//cout << Input[i][j] << endl;
}
j2++;
}
return 0;
}
int main() {
//Define a matrix for test:
vector<vector<int>> Matrix2(4, vector<int>(5, 1));
int R = 4;
int C = 4;
vector<vector<int>> MatrixInput(R, vector<int>(C, 1));;
for (int i = 0; i < MatrixInput.size(); i++) {
for (int j = 0; j < MatrixInput[0].size(); j++) {
int temp;
temp = i^2+j^2;
MatrixInput[i][j] = temp;
}
}
MatrixSlice(MatrixInput, 0, 3, 1, 1);
printf("\n");
return 0;
}
Matrix slice has a couple problems:
It is impossible define a variable with two possible types and have both active in the same scope.
The return type of int makes little sense. The matrix is sliced up, but then what? It can't be handed back to the caller to do anything with it.
This can be fixed with a union, but yikes! The bookkeeping on that will be a Smurfing nightmare. Don't do it!
The next is to always use a vector of vectors, but I don't like that idea for a couple reasons I'll get into below.
Instead I pitch a simple wrapper object around a single vector. This is done for two reasons:
It preserves the ability to back a 1 dimensional matrix with a 1 dimensional container. If you have many rows of one column, all of the row data remains contiguous and cache friendly.
It tends to be much faster. The data of one vector is contiguous in memory and reaps the rewards of cache friendliness. A vector of vectors is basically a list of pointers to arrays of data, sending the poor CPU on an odyssey of pointer-chasing through memory to find the columns. If the columns are short, this can really, really hurt performance.
Here we go:
template<class TYPE>
class Matrix
{
private:
size_t mNrRows; // note size_t. This is unsigned because there is no reason
// for a matrix with a negative size. size_t is also guaranteed
// to fit anything you can throw at it.
size_t mNrColumns;
std::vector<TYPE> mVec;
public:
// make a default-initialized matrix
Matrix(size_t nrRows, size_t nrColumns) :
mNrRows(nrRows), mNrColumns(nrColumns), mVec(mNrRows * mNrColumns)
{
}
// make a def-initialized matrix
Matrix(size_t nrRows, size_t nrColumns, TYPE def) :
mNrRows(nrRows), mNrColumns(nrColumns), mVec(mNrRows * mNrColumns,
def)
{
}
// gimme a value and allow it to be changed
TYPE & operator()(size_t row, size_t column)
{
// could check for out of bounds and throw an exception here
return mVec[row * mNrColumns + column];
}
//gimme a value and do not allow it to be changed
TYPE operator()(size_t row, size_t column) const
{
return mVec[row * mNrColumns + column];
}
// gimme the number of rows
size_t getRows() const
{
return mNrRows;
}
// gimmie the number of columns.
size_t getColumns() const
{
return mNrColumns;
}
// printing convenience
friend std::ostream & operator<<(std::ostream & out, const Matrix & mat)
{
int count = 0;
for (TYPE val: mat.mVec)
{
out << val;
if (++count == mat.mNrColumns)
{
out << '\n';
count = 0;
}
else
{
out << ' ';
}
}
return out;
}
};
The vector member handles all of the heavy lifting so the Rule of Zero recommends leaving the copy and move constructors, assignment operators, and destructor up to the compiler.
What does this do to MatrixSlice? Well, first it now received and returns a Matrix instead of vector<vector> and int. The insides use Matrix and the confusion about 1D or 2D is just plain gone, resulting in a simpler function.
Matrix<int> MatrixSlice(const Matrix<int> & Input,
int Row1,
int Row2,
int Col1,
int Col2)
{
Matrix<int> OutPut(Row2-Row1 + 1,
Col2-Col1 + 1); // but what if Row1 > Row2?
int i2;
int j2= 0; // definitely need to initialize this sucker.
for (int i = Row1; i <= Row2; i++) // logical problem here: What if Row2 >= input.getRows()?
{
i2 = 0;
for (int j = Col1; j <= Col2; j++) // similar problem here
{
int DumyValue = Input(i, j);
OutPut(j2, i2) = DumyValue;
i2++;
}
j2++;
}
return OutPut;
}
Not that this completely ignores the very logical option of making slice a Matrix method. While it makes sense, it doesn't need to be a method and the stock recommendation is to prefer a free function. One good improvement is to make the function a template so that it can handle all sorts of Matrix in addition to Matrix<int>.
And finally, what happens to main?
int main()
{
//Define a matrix for test:
Matrix<int> Matrix2(4, 5, 1); // initialize matrix to all 1s
int R = 4;
int C = 4;
Matrix<int> MatrixInput(R, C); // default initialize the matrix
for (int i = 0; i < MatrixInput.getRows(); i++)
{
for (int j = 0; j < MatrixInput.getColumns(); j++)
{
int temp;
temp = i ^ 2 + j ^ 2;
// WARNING: ^ is XOR, not exponent. Maybe OP wants i XOR 2, but not
// likely. But if XOR is the desired operation, there is a lurking
// order of operation bug that needs to be addressed
MatrixInput(i, j) = temp;
}
}
std::cout << MatrixInput << '\n';
std::cout << MatrixSlice(MatrixInput, 0, 3, 1, 1);
return 0;
}
In your code
if (abs(Row1-Row2)>1 && abs(Col1-Col2)>1){
vector<vector<int> > OutPut;
// OutPut dies here
}else{
vector<int> OutPut;
// OutPut dies here
}
// here is no OutPut
OutPut lives only to the end of IF statement.
You either use it without the if statement or you add all code that uses it to the if statement.
I am making a class to do matrix (and vector) math for a test I am running and to learn more C++. The class looks like this:
class utlMatrix
{
private:
int num_rows;
int num_cols; // number of columns
double **data; // array of pointers to the data
public:
// default constructor, with initialization
utlMatrix() : num_rows(0), num_cols(0), data(NULL) {};
// constructor with size
utlMatrix(int, int);
// destructor
~utlMatrix();
// copy constructor
utlMatrix(const utlMatrix&);
void copy(const utlMatrix &old); // copy 'old' to 'this'
void zero(); // sets all values to zero
void fill_rand(); //fills the data with random stuff
void print(std::ostream&); // prints the matrix to a file
// Operators
utlMatrix& operator=(const utlMatrix&); // copies matrices
friend utlMatrix operator+(const utlMatrix&, const utlMatrix&); // adds 2 matrices
utlMatrix operator*(const utlMatrix&) const;
//friend utlMatrix operator*(const utlMatrix&, const utlMatrix&); // multiplies 2 matrices
};
Copy Constructors, assignment operator and destructor
// copy constructor
utlMatrix::utlMatrix(const utlMatrix &old) {
copy(old);
}
utlMatrix& utlMatrix::operator=(const utlMatrix &old) {
copy(old);
return *this;
}
void utlMatrix::copy(const utlMatrix &old) {
num_rows = old.num_rows;
num_cols = old.num_cols;
data = new float*[num_rows];
for (int i = 0; i < num_cols; i++)
data[i] = new float[num_cols];
for (int i = 0; i < num_rows; i++)
{
for (int j = 0; j < num_cols; j++)
data[i][j] = old.data[i][j];
}
}
utlMatrix::~utlMatrix()
{
for (int i = 0; i < num_rows; i++)
delete [] data[i];
delete [] data;
}
Multiplication operators, I tried both, both failed if used twice in a row.
/*
utlMatrix operator*(const utlMatrix &left, const utlMatrix &right)
{
// first determine if the matrices can be multiplied
if (left.num_cols != right.num_rows)
{
std::cout << "Error using *, Inner dimensions must agree." << std::endl;
exit(-1);
}
// create the new matrix
utlMatrix newmat(left.num_rows, right.num_cols);
for (int i = 0; i < left.num_rows; i++)
for (int j = 0; j < right.num_cols; j++)
for (int k = 0; k < right.num_rows; k++)
newmat.data[i][j] += left.data[i][k] * right.data[k][j];
return newmat;
}
*/
utlMatrix utlMatrix::operator*(const utlMatrix &right) const
{
if ( this->num_cols != right.num_rows)
{
std::cout << "Error using *, Inner dimensions must agree." << std::endl;
return utlMatrix();
}
utlMatrix newmat(this->num_rows, right.num_cols);
for (int i = 0; i < this->num_rows; i++)
for (int j = 0; j < right.num_cols; j++)
for (int k = 0; k < right.num_rows; k++)
newmat.data[i][j] += this->data[i][k] * right.data[k][j];
return newmat;
}
The copy constructor, assignment and addition operators all work fine. When I try to multiply 1 matrix by another it works the first time but fails on the second. I altered the code to write out when it enter a constructor, operator and destructor in addition to printing the matrices after the multiplication. The math is good for the first matrix and the code fails with:
Unhandled exception at 0x776015de in sandbox.exe: 0xC0000005: Access violation writing location 0xcdcdcdcd.
From the screen output I know this is happening after the copy constructor is called following the second multiplication. The addition operator mirrors the first multiplication operator and appears to work fine, no exceptions, the copy constructor and destructor happen as expected. I found 2 answers on SO, Matrix class operator overloading,destructor problem and Matrix Multiplication with operator overloading. I checked to make sure that my pointers were not copied. The copy constructor does create a new object with a new pointer to data. If I run:
int main()
{
utlMatrix A(3,3);
utlMatrix B(2,2);
A.fill_rand();
B.fill_rand();
B = A;
return 0;
}
The debugger shows:
A {num_rows=3 num_cols=3 data=0x000365c0 ...} utlMatrix
B {num_rows=3 num_cols=3 data=0x00037c50 ...} utlMatrix
What did I miss? Here is how I actually used the operator. Failure occurs after D = A * B;
#include "utlMatrix.h"
int main()
{
// create the first matrices
utlMatrix A(3,3);
utlMatrix B(3,3);
utlMatrix C(3,2);
// fill them with random numbers
A.fill_rand();
B.fill_rand();
C.fill_rand();
utlMatrix D = A * B;
utlMatrix E = A * C;
utlMatrix F = B * C;
}
The error appeared to only show itself after the second or third call because that was when the matrices produced non-square output. These lines:
for (int i = 0; i < num_cols; i++)
data[i] = new float[num_cols];
in the copy constructor meant the non-square matrix was actually being built as a square matrix of size columns of the old one. Since my case was a matrix with more rows than columns it tried to put data into a non-existing memory location. Following the suggestions of Igor Tandetnik and Dave S, fixing the indexes and using SWAP fixed the problem.