The other day I was trying to write a matrix manipulation program in C++. I first created a matrix container which works. Then I tried to write a function for transposing matrices. That's when I got into trouble. Using the function causes my program to crash.
struct imat //matrix of integer numbers
{
friend int size(imat,int);
protected:
const int nrows; const int ncols; //ncols = number of columns, nrows = number of rows
int* mat; //internal array that holds the data
public:
imat(const int m, const int n): nrows(m), ncols(n) //constructor
{
mat = new int[m*n]; //creates an array of size nrows*ncols
for (int k=0; k<m*n; k++) mat[k]=0; //zeros all the elements
}
imat(const imat& src): nrows(src.nrows), ncols(src.ncols) //copy constructor
{for (int k=0; k<nrows*ncols; k++) mat[k]=src.mat[k];} //copies the contents of src to this matrix
imat& operator=(const imat& rhs) //assignment operator
{
if (nrows!=rhs.nrows||ncols!=rhs.ncols) throw(1); //lhs and rhs must have the same dimensions
for (int k=0; k<nrows*ncols; k++) mat[k]=rhs.mat[k]; //copies the contents of rhs to this matrix (lhs)
return *this; //return this matrix as output (lhs)
}
int& operator()(int i, int j) {return mat[(i-1)*ncols+(j-1)];} //A(i,j)=mat[(i-1)*ncols+(j-1)] (stores the matrix in the 1D array 'mat')
~imat() {delete[] mat;}
};
int size(imat mat, int dim) //gets matrix dimensions
{
if (dim==1) return mat.nrows; //dimension 1 is number of rows
if (dim==2) return mat.ncols; //dimernsion 2 is number of columns
return 0; //returns 0 if dimesion number is invalid
}
imat trans(imat A)
{
int m=size(A,1); //number of rows
int n=size(A,2); //numbers of columns
imat B(n,m); //creates an n*m matrix
for (int i=1; i<=m; i++)
for (int j=1; j<=n; j++)
B(j,i)=A(i,j); //sets the components of B to the components of the transpose of A
return B;
}
I tried the following main functions, but none of them works:
1)
int main()
{
imat A(2,3);
A(1,1)=11;
A(1,2)=12;
A(1,3)=13;
A(2,1)=21;
A(2,2)=22;
A(2,3)=23;
imat B = trans(A);
return 0;
}
2)
int main()
{
imat A(2,3);
A(1,1)=11;
A(1,2)=12;
A(1,3)=13;
A(2,1)=21;
A(2,2)=22;
A(2,3)=23;
imat B(3,2)
B = trans(A);
return 0;
}
My guess is that it has something to do with the destruction of objects at the end of a function scope, though I'm not sure. Please explain to me in simple language what the problem is and how I can fix it.
You forgot to allocate memory for your dynamic array in the copy constructor. You just started assigning to mat[...], even though mat was left uninitialized.
Related
the following code is not giving the correct output. Matrix data is displaying perfectly, but after the addition of two objects M1 and M2, it did not display the correct output. If I use setData to input data in the matrix, data is stored perfectly, but the addition is not performing correctly. kindly suggest to me how can I correct this logical error?
#include <iostream>
#include <string.h>
using namespace std;
class Matrix{
private:
void Allocate();
int noOfRows;
int noOfColumns;
int **data;
public:
Matrix(int noOfRows, int noOfColumns);
void setData();
void displayData();
~Matrix();
Matrix (const Matrix &ref);
Matrix operator + (const Matrix &m);
void operator = (const Matrix &M );
Matrix& operator = (int x);
};
Matrix::Matrix(int inr=0, int inc=0){
noOfRows=inr; noOfColumns=inc;
Allocate();
}
Matrix::Matrix (const Matrix &ref){
Allocate();
for(int r=0;r<ref.noOfRows;r++)
for(int c=0;c<ref.noOfColumns;c++)
data[r][c]=ref.data[r][c];
}
void Matrix :: operator = (const Matrix &M ) {
Allocate();
noOfRows = M.noOfRows;
noOfColumns = M.noOfColumns;
data=M.data;
}
Matrix& Matrix :: operator = (int x){
Allocate();
for(int r=0;r<noOfRows;r++)
for(int c=0;c<noOfColumns;c++)
data[r][c]=x;
return *this;
}
void Matrix::Allocate(){
data=new int*[noOfRows];
for(int i=0;i<noOfRows;i++)
data[i]=new int[noOfColumns]();
}
void Matrix::setData(){
for(int r=0;r<noOfRows;r++){
for(int c=0;c<noOfColumns;c++){
cout<<"Enter ...";cin>>data[r][c];
}
cout<<endl;
}
}
Matrix Matrix::operator + (const Matrix &m){
Matrix ms(m.noOfRows,m.noOfColumns);
for (int i=0; i<m.noOfRows; i++)
for (int j=0; j<m.noOfColumns; j++)
ms.data[i][j] = data[i][j]+m.data[i][j];
return ms;
}
void Matrix::displayData(){
for(int r=0;r<noOfRows;r++){
for(int c=0;c<noOfColumns;c++)
cout<<data[r][c]<<"\t";
cout<<endl;
}
}
Matrix::~Matrix(){
for (int i = 0; i < noOfRows; ++i)
delete[] data[i];
delete [] data;
}
int main(){
Matrix M3(2,2);M3=0;
Matrix M1(2,2);M1=1;
Matrix M2(2,2);M2=2;
//M1.setData();M2.setData();M3.setData();
cout<<"\n Matrix A = "<<endl;
M1.displayData();
cout<<"\n Matrix B = "<<endl;
M2.displayData();
cout<<"\n Matrix C = "<<endl;
M3 = M1;
M3.displayData();
cout<<"\n Sum of Matrix = "<<endl;
M3 = M1 + M2;
M3.displayData();
return 0;
}
Output is here for detail
Copy constructor and assignment operator were both broken. Let's take a quick stroll to see what went wrong
Matrix::Matrix (const Matrix &ref){
// noOfRows and noOfColumns have not been initialized. Their values are unknown so
// the rest of this function is a crapshoot. Could do anything.
Allocate();
for(int r=0;r<ref.noOfRows;r++)
for(int c=0;c<ref.noOfColumns;c++)
data[r][c]=ref.data[r][c];
}
// An assignment operator is expected to return Matrix &
void Matrix :: operator = (const Matrix &M ) {
// noOfRows and noOfColumns have not been updated. Could be wrong, resulting in
// allocate allocating the wrong amount of storage. Moot point since this
// allocation is never used. See below.
Allocate();
noOfRows = M.noOfRows;
noOfColumns = M.noOfColumns;
data=M.data; // both instances share M's data. This will fail sooner or later
// If the program lives long enough, both instances will go out
// of scope and double delete the allocation.
// Also leaks allocation pointed at by `data`.
}
I was in a hurry so I didn't put much thought into fixing the assignment operator and just used the Copy and Swap Idiom. It's very possible that there is a more efficient solution, but copy and swap is usually fast enough and almost impossible to get wrong. Makes a great starting point and benchmarking will tell you if it's a problem.
Matrix::Matrix(const Matrix &ref):
noOfRows(ref.noOfRows),
noOfColumns(ref.noOfColumns) // initialize row and columns
{
Allocate(); // now safe to use
for (int r = 0; r < ref.noOfRows; r++)
for (int c = 0; c < ref.noOfColumns; c++)
data[r][c] = ref.data[r][c];
}
Matrix& Matrix::operator =(Matrix M) // correct return type, and does the heavy
// lifting with the copy constructor
{
std::swap(noOfRows, M.noOfRows);
std::swap(noOfColumns, M.noOfColumns);
std::swap(data, M.data);
return *this;
}
The following code gives me the wrong output. actually, it is not doing sum, it actually copies the 2nd object to the M3 object instead of calculating the sum. I think I have some logical errors in + operator overloading. Does anybody have any idea or any other suggestion? it displays the output actually which is called in the copy constructor function cout<data[r][c]<<"\t";. but it did not display output when I use M3.displayData().
#include
#include <string.h>
using namespace std;
class Matrix{
private:
int noOfRows;
int noOfColumns;
int **data;
public:
Matrix(int noOfRows, int noOfColumns);
void displayData();
~Matrix();
Matrix (const Matrix &ref);
Matrix operator + (Matrix m);
Matrix& operator=(Matrix m) {
std::swap(m.noOfRows, noOfRows);
std::swap(m.noOfColumns, noOfColumns);
std::swap(m.data, data);
return *this; }
};
Matrix::Matrix(int inr=0, int inc=0){
noOfRows=inr; noOfColumns=inc;
data=new int*[noOfColumns];
for(int i=0;i<noOfRows;i++)
data[i]=new int[noOfColumns];
int d;
for(int r=0;r<noOfRows;r++){
for(int c=0;c<noOfColumns;c++){
cout<<"Enter ...";cin>>d;
data[r][c]=d;
}
cout<<endl;
}
}
Matrix::Matrix (const Matrix &ref){
this->data=new int*[ref.noOfColumns];
for(int i=0;i<ref.noOfRows;i++)
this->data[i]=new int[ref.noOfRows];
for(int r=0;r<ref.noOfRows;r++){
for(int c=0;c<ref.noOfColumns;c++){
this->data[r][c]=ref.data[r][c];
cout<<this->data[r][c]<<"\t";
}
cout<<endl;
}
}
Matrix Matrix::operator + (Matrix m){
Matrix ms(m.noOfRows,m.noOfColumns);
ms=0;
for (int i=0; i<m.noOfRows; i++)
for (int j=0; j<m.noOfColumns; j++){
ms.data[i][j] = data[i][j]+m.data[i][j];
return ms;
}
}
void Matrix::displayData(){
for(int r=0;r<noOfRows;r++){
for(int c=0;c<noOfColumns;c++)
cout<<data[r][c]<<"\t";
cout<<endl;
}
}
Matrix::~Matrix(){
delete[] data;
}
int main(){
Matrix M1(2,2),M2(2,2);
cout<<"\n Matrix A="<<endl;
M1.displayData();
cout<<"\n Matrix B="<<endl;
M2.displayData();
cout<<"\n Sum of Matrix="<<endl;
Matrix M3=M1+M2;
M3.displayData();
return 0;
}
There are at least four issues with your code:
The Matrix copy constructor fails to copy the noOfRows and noOfColumns values.
You erroneously allocated the row pointers by using noOfColumns as the number of rows.
In the Matrix operator +, you are returning the Matrix inside the for loop, when you should be returning it after the loop is completed.
Your destructor fails to delete[] all the row and column data.
To fix the first two issues, since there is a lot of common code between the Matrix default constructor and the copy constructor, you could create an Allocate member function to allocate the memory:
class Matrix
{
private:
void Allocate();
//... other members
public:
Matrix operator + (const Matrix& m);
// other members...
};
Matrix::Matrix(int inr=0, int inc=0) : noOfRows(inr), noOfColumns(inc)
{
Allocate();
// Input code removed...
}
Matrix::Matrix (const Matrix &ref) : noOfRows(ref.noOfRows), noOfColumns(ref.noOfColumns)
{
Allocate();
for(int r=0; r < ref.noOfRows; r++)
{
for(int c=0; c < ref.noOfColumns; c++)
data[r][c] = ref.data[r][c];
}
}
void Matrix::Allocate()
{
data=new int*[noOfRows];
for(int i=0;i < noOfRows; i++)
data[i]=new int[noOfColumns]();
}
For operator +, you should pass the Matrix by const reference, not by value (this is in addition to fixing the mistake of returning the Matrix prematurely):
Matrix Matrix::operator + (const Matrix& m)
{
Matrix ms(m.noOfRows,m.noOfColumns);
for (int i=0; i<m.noOfRows; i++)
{
for (int j=0; j<m.noOfColumns; j++)
ms.data[i][j] = data[i][j]+m.data[i][j];
}
return ms;
}
The last issue (the destructor) only removes the row pointers, but does not remove the data allocated for each row. The fix is below:
Matrix::~Matrix()
{
for (int i = 0; i < noOfRows; ++i)
delete[] data[i];
delete [] data;
}
Other issues:
Put more space between operators. Your current code squishes everything together, making it hard to read. For example:
for(int c=0;c<ref.noOfColumns;c++) could be:
for (int c=0; c < ref.noOfColumns; c++)
Excessive and unnecessary usage of this->.
If Matrix::operator + exists, it makes sense for Matrix::operator += to also exist. For the latter, operator + would simply be implemented in terms of operator +=, making operator + one or two lines of code.
A probably better method of allocating the memory is illustrated by this answer, since only two allocations are done, the memory allocated is contiguous, and less memory fragmentation will occur.
Working on a program involving matrices and hit with an error involving Multiply and Transpose methods. I'm not sure how to proceed
//Header file
class Matrix
{
public:
Matrix(); // constructor
void initIdentity(int n); // initialize as an identity matrix of size nxn
void initFromFile(string fileName); // read the matrix from a file
bool isSquare(); // test whether matrix is square
int numRows(); // return number of rows
int numCols(); // return number of columns
double getVal(int row, int col); // return matrix value at given row/col location (0-indexed based)
void setVal(int row, int col, double val); // set the matrix value at given row/col location (0-index based)
Matrix Multiply(Matrix B); // post-multiply by B and return resulting matrix
Matrix Multiply(double A); // multiply by a scalar and return resulting matrix
Matrix Transpose(); // return transpose of matrix
vector<double> Diagonal(); // return a vector containing diagonal elements of the matrix
void Print(); // print the matrix to stdout
void Print(string name); // print the matrix to stdout with a name prefix
Matrix(int row, int col, double val); // initializing a matrix
private:
vector< vector<double> > matrix_;
vector< vector<int> > identMatrix_;
vector<double> innerVec_;
int numRows_;
int numCols_;
};
//Main file
Matrix Matrix::Multiply(double A){
Matrix ans(numRows_, numCols_, 0.0);
for (int i=0; i< numRows_; i++){
for (int j=0; j< numCols_; j++){
ans(i, j) = matrix_[i][j] * A;
}
}
return ans;
}
Matrix Matrix::Transpose(){
Matrix ans(numRows_, numCols_, 0.0);
for (int i=0; i<numRows_; i++){
for (int j=0; j<numCols_; j++){
ans(i, j) = matrix_[j][i];
}
}
return ans;
}
Error:
Main.cpp:110:7: error: type 'Matrix' does not provide a call operator
ans(i, j) = matrix_[i][j] * A;
^~~
Main.cpp:120:5: error: type 'Matrix' does not provide a call operator
ans(i, j) = matrix_[j][i];
^~~
As noted in comments, you have:
ans(i, j) = matrix_[i][j] * A;
Which is trying to call operator() on ans. But you haven't defined this operator for this type of object.
You'd either need to define that operator so this code works, or just use the existing setVal:
ans.setVal(i, j, matrix_[i][j] * A);
I'm trying to use clear functions to do a matrix multiplication with random generated values. Therefore I'm hoping to use a function(mat_def) to generate the matrices and another function(mat_mul) to multiply them when the matrices are sent as parameters.
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
double mat_def(int n) //how to return the matrix
{
double a[n][n];
double f;
for(int i=0; i<n; i++)
{
for(int j=0; j<n; j++)
{
f= rand();
cout<<f ;
a[i][j]=f;
}
}
return 0;
}
double mat_mul( int n, double a[n][n], double b[n][n]) //how to send matrix as parameter
{
return 0;
}
int main()
{
/* initialize random seed: */
srand (time(NULL));
mat_def(10);
}
Here's a nice, standard C++ Matrix template for you.
Matrix.h
#include <vector>
class Matrix
{
class InnerM
{
private:
int ydim;
double* values;
public:
InnerM(int y) : ydim(y)
{
values = new double[y];
}
double& operator[](int y)
{
return values[y];
}
};
private:
int xdim;
int ydim;
std::vector<InnerM> inner;
public:
Matrix(int x, int y) : xdim(x), ydim(y), inner(xdim, InnerM(ydim))
{
}
InnerM& operator[](int x)
{
return inner[x];
}
};
All the memory leaks are there for you but you get the idea. From here you can handle the multiplication by overiding ::operator*() in the Matrix class.
I assume your problem is to define 2-D array and then pass it to mat_mul function to multiply the matrices. And the rest will be quite simple.
Defining the 2-D array(considering memory needs are known at run time):
int rows,cols;
cin >> rows;
cin >> cols;
int **arr = new int*[rows]; // rows X cols 2D-array
for(int i = 0; i < rows; ++i) {
arr[i] = new int[cols];
}
You can define another 2-D array exactly the same way with required rows and column.
now, Passing the 2-D array to function:
void mat_mul(int **arr1, int **arr2, int m, int n, int p, int q){
//define a 2-D array to store the result
//do the multiplication operation
//you could store the result in one of the two arrays
//so that you don't have to return it
//or else the return type should be modified to return the 2-D array
}
example:
void display(int **arr, int row, int col){
for (int i=0; i<row; i++){
for(int j=0;j<col; j++){
cout << arr[i][j] << '\t';
}
cout << endl;
}
}
Delete the memory if not required anymore with the following syntax:
for(int i=0; i<rows; i++){
delete[] array[i];
}
delete[] array;
hope this will be sufficient to get your work done!
there is already an answer on how to return a 2-D array on SO. Check the link below.
https://stackoverflow.com/a/8618617/8038009
Returning the raw allocation is a sucker bet. You need to manage all of the memory allocated yourself and pass it around with the matrix size parameters.
Why suffer? Use a matrix class
template<class Type>
class Matrix{
int rows;
int cols;
std::vector<type> data;
public:
Matrix(int row, int col):rows(row), cols(col), data(rows*cols)
{
// does nothing. All of the heavy lifting was in the initializer
}
// std::vector eliminates the need for destructor, assignment operators, and copy
//and move constructors.
//add a convenience method for easy access to the vector
type & operator()(size_t row, size_t col)
{
return data[row*cols+col];
}
type operator()(size_t row, size_t col) const
{
return data[row*cols+col];
}
};
Usage would be
Matrix<double> mat_mul(const Matrix<double> &a, const Matrix<double> &b)
{
Matrix<double> result;
// do multiplication
return result;
}
int main()
{
/* initialize random seed: */
srand (time(NULL));
Matrix<double> matA(10, 10);
matA(0,0) = 3.14; // sample assignment
matA(9,9) = 2.78;
double x = matA(0,0) * matA(9,9)
Matrix<double> matB(10, 10);
Matrix<double> matC = mat_mul(matA, matB) ;
}
More functionality, such as construction from an initializer list, can be added to the class to make your life easier. You can also specify an operator * overload for Matrix and use that in place of mat_mul if you chose. Read Operator overloading for more on that option.
I have matrix class, and two constructors- one which have arguments (rows,cols,number), for example matrix c(4,4,4) will create 4x4 matrix and fill it with number 4.
Second constructor is reading matrix from txt file, and if I print it in constructor everything works fine, but I wanted to overload ostream << operator to print matrix in main function. This operator works for first constructor but doesn't work for the second one, it prints random numbers in infinity loop.
Here's my code, thanks for any advice and help.
ostream & operator <<(ostream &o, const matrix &m)
{
for(int r=0; r<m.rows;r++)
{
for(int c=0; c<m.cols;c++)
{
o<<m.mat[r][c]<<" ";
}
o<<endl;
}
return o;
}
matrix::matrix(const char* file_name)
{
int rows=0;
int cols=0;
FILE *fp;
fp=fopen(file_name,"rb");
fseek(fp,0,SEEK_SET);
fscanf(fp,"%d",&rows);
fscanf(fp,"%d",&cols);
mat=new double*[rows];
for(int i=0;i<rows;i++)
{
mat[i]=new double[cols];
}
for(int k=0;k<rows;k++)
{
for(int j=0;j<cols;j++)
{
fscanf(fp,"%lf",&mat[k][j]);
//cout<<mat[k][j]; it works.
}
cout<<endl;
}
}
EDIT: added first constructor:
matrix::matrix(int r, int c, double n)
{
rows=r;
cols=c;
mat= new double*[rows];
for(int i=0;i<rows;i++)
{
mat[i]=new double[cols];}
for(int k=0;k<rows;k++)
{
for(int j=0;j<cols;j++)
{
mat[k][j]=n;}
}
}
It seems like your "not-working" constructor has an error indeed. That's because you have defined rows and cols as local variables, so the members rows and cols of the matrix object are not set.
Try removing those local definitions, so that the rows and cols referenced are actually your object's data members. Remove the lines:
int rows=0;
int cols=0;
Or replace them with:
rows = cols = 0;