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.
Related
I want to do something like:
int a[][]; // I know this code won't work, its to demonstrate what I want to do
void func(int n, int m){
a = int[n][m];
}
that is, initialise a global array whose size depends on function input. If this array was local, it would be a trivial case, but I don't know how to do this in the case shown above. Any help would be very useful!
You can create a matrix with std::vector:
std::vector<std::vector<int>> a;
void func(int n, int m) {
a.resize(n);
for(int i = 0; i < n; i++) {
a[i].resize(m);
}
}
Then you can access elements in the same way you do with int a[][]:
a[i][j] = number;
One way to achieve this is to encapsulate a flat std::vector in a Matrix class and use math to get an element with row and column as in this example:
template<typename T>
class Matrix {
private:
vector<T> vec;
//...
public:
T& get_value(size_t const row, size_t const col) {
return vec[row * col_count + col];
}
};
you can try this
int ** a; // is a pointer of two dimension
void func(int n, int m){
a = new int*[n]; //dynamic allocation global pointer a
for(int i = 0; i < n; i++)
a[i] = new int[m]();
}
int** transpose(int** matrix,int row, int column)
{
int** new_mat = new int*[column];
for(int i = 0; i < column; i++)
{
new_mat[i] = new int[row];
}
for(int i = 0; i < row; i++ )
{
for(int j = 0; j < column; j ++)
{
new_mat[j][i] = matrix[i][j];
}
}
return new_mat;
}
I have written this function but something feels wrong I couldn't decide whether should I delete new_mat somehow basically function returns this value how should I manage with memory without using any smart pointers or something?
The caller would use the returned matrix.
Moreover, it could acquire ownership. As a result, when the matrix would be no longer needed, it could delete it.
Another option, is for you, to provide another function, that will delete the matrix. The caller then, must call that function to de-allocate the dynamically allocated memory.
However, smart pointers is a nice C++ feature, and I encourage you to give them a shot.
Furthermore, since this C++, you could use a std::vector<std::vector<int>> for the type of your matrix. That way, you don't have to worry about memory management, since everything about it, will happen automatically.
To answer the question as asked, the caller would need to release the returned pointer. For every usage of operator new in the function, there needs to be a corresponding usage of operator delete in the caller. The caller would do this when the matrix returned is no longer needed i.e. anything that is deleted should not subsequently be used.
A better approach - in many respects, including no potential to forget to release memory - is to avoid using pointers directly, avoid using operator new (or variants) or operator delete directly. Instead, use a standard container, such as std::vector(std::vector<int> >. If used carefully, standard containers manage their own elements, and keep a record of their own size, so there is no possibility of memory leak (when a standard container ceases to exist, any dynamically allocated memory it uses also is released).
In principle, you should be able to simplify your function to something that is declared as
std::vector<std::vector<int> > transpose(const std::vector<std::vector<int> > &matrix);
rather than needing to pass numbers of rows and columns as separate arguments (the vectors will keep track). I'll leave implementing that function as an exercise, since you'll learn more of use that way.
You really should think about your matrix representation:
int** matrix = ...; // create matrix of 10x12
// doing quite a lot of stuff
delete[] matrix[7]; // possibly even forgotten -> memory leak
matrix[7] = new int[7];
and you now have a jagged array. Although std::vector will relieve you from all the memory management stuff, you still won't be able to prevent jagged arrays with:
std::vector<std::vector<int>> matrix = ...; // create matrix of 10x12
// doing quite a lot of stuff
matrix[7].resize(7);
Safest thing you can do is create your own class wrapping around the data; I'll be using std::vectors to hold the data, this will make the whole memory management stuff much easier:
template <typename T> // more flexibility: you can use arbitrary data types...
class Matrix // (but you don't _need_ to make a template from)
{
std::vector<std::vector<T>> data;
public:
Matrix(size_t rows, size_t columns)
: data(rows)
{
for(auto& d : data)
d.resize(columns);
}
// the nice thing about using std::vector as data container is
// that default generated move/copy constructors/assignment
// operators and destructor are fine already, so you can forget
// about rule of three or five respectively
// but you need ways to access your data:
size_t rows() { return data.size(); }
size_t columns() { return data.empty() ? 0 : data[0].size(); }
??? operator[](size_t index);
??? operator[](size_t index) const;
};
Well, the index operators... What you actually want to achieve is something that you can access the matrix just like you did with your arrays:
Matrix<int> m(10, 12);
m[7][7] = 7;
But what should we return? A reference to an inner vector would again allow to modify its size and to create a jagged array this way. Solution: A wrapper class around!
template <typename T>
class Matrix
{
// all we had so far...
template <typename Data>
class Row
{
Data& data;
friend class Matrix;
Row(std::vector<T>& data)
: data(data)
{ }
public:
// default constructed constructors/operators/destructor
// themselves and being public are fine again...
auto& operator[](size_t index) { return data[index]; }
};
auto operator[](size_t index) { return Row(data[index]); }
auto operator[](size_t index) const { return Row(data[index]); }
};
Why Row a template? Well, we need different Row types (mutable and immutable access to data) as return types for the two different index operators...
Finally: If you implement yourself, I'd reorder the private/public sections such that public comes first. This improves readability for users of your Matrix class, as they are interested in public interface only (normally) unless they intend to inherit from. But that (currently) is not a good idea here anyway as this class is not intended for, just as std::vector is not either. If you want that: make the destructor virtual:
virtual ~Matrix() = default;
If you feel more comfortable with, you could make the rule of three/five explicit:
Matrix(Matrix const& other) = default; // rule of three
Matrix& operator=(Matrix const& other) = default; // rule of three
Matrix(Matrix&& other) = default; // rule of five
Matrix& operator=(Matrix&& other) = default; // rule of five
Analogously for Row class. Be aware that if you insist on using raw arrays inside then you will have to write all of these explicitly!
Transposing matrices could then be done via a free function again:
Matrix transpose(Matrix const& m)
{
Matrix t(m.columns(), m.rows());
// loops as you had
return t;
}
You could even provide a member function that transposes the matrix itself, best: use above transpose function:
template <typename T>
class Matrix
{
public:
void transpose()
{
Matrix t(transpose(*this));
t.data.swap(data); // cleanup of previously owned data done in t's destructor...
}
If you don't want to use any smart pointers and vectors, then try like this.
matrix - is a wrapper for 2D-dynamic array with size [col][row].
#include <iostream>
#include <algorithm>
using namespace std;
class matrix
{
private:
unsigned int m_row;
unsigned int m_col;
int **m_data;
public:
matrix(unsigned int row, unsigned int col) : m_row(row), m_col(col), m_data(nullptr)
{
alloc();
}
matrix(const matrix &m) : m_row(m.get_rows_count()), m_col(m.get_cols_count()), m_data(nullptr)
{
alloc();
for(unsigned int i = 0; i < m_row; i++)
for(unsigned int j = 0; j < m_col; j++)
m_data[i][j] = m[i][j];
}
~matrix()
{
free();
}
unsigned int get_rows_count() const { return m_row; }
unsigned int get_cols_count() const { return m_col; }
const int* operator[](unsigned int ind) const
{
return m_data[ind];
}
int* operator[](unsigned int ind)
{
return m_data[ind];
}
matrix& operator=(const matrix &m)
{
free();
m_row = m.get_rows_count();
m_col = m.get_cols_count();
alloc();
for(unsigned int i = 0; i < m_row; i++)
for(unsigned int j = 0; j < m_col; j++)
m_data[i][j] = m[i][j];
return *this;
}
// you need move-operations:
//matrix(matrix&& other) = delete; // move constructor (rule of 5)
//matrix& operator=(matrix&& other); // move assignment (rule of 5)
void print()
{
for(unsigned int i = 0; i < m_row; i++)
{
for(unsigned int j = 0; j < m_col; j++)
cout << m_data[i][j] << " ";
cout << endl;
}
}
private:
void alloc()
{
if(m_data)
return;
m_data = new int*[m_row];
for(unsigned int i = 0; i < m_row; i++)
{
m_data[i] = new int[m_col];
std::fill(m_data[i], m_data[i] + m_col, 0);
}
}
void free()
{
if(!m_data)
return;
for(unsigned int i = 0; i < m_row; i++)
delete[]m_data[i];
delete[]m_data;
m_data = nullptr;
}
};
matrix transpose(const matrix matrix_in)
{
unsigned int M = matrix_in.get_rows_count();
unsigned int N = matrix_in.get_cols_count();
matrix out(N, M);
for(unsigned int i = 0; i < M; i++)
for(unsigned int j = 0; j < N; j++)
out[j][i] = matrix_in[i][j];
return out;
}
int main(int argc, char* argv[])
{
matrix m1(5, 7);
m1[0][1] = m1[0][2] = m1[0][3] = 7;
auto m2 = transpose(m1);
m1.print();
cout << endl;
m2.print();
}
In any case, it is better to free the memory in the same place where it was allocated. If you do not want to use some classes, you can do it like this:
void transpose(int **matr_in, int **matr_out, int M, int N)
{
for(int i = 0; i < M; i++)
for(int j = 0; j < N; j++)
matr_out[j][i] = matr_in[i][j];
}
int **create_matrix(int M, int N)
{
int **m = new int*[M];
for(int i = 0; i < M; i++)
m[i] = new int[N];
return m;
}
void delete_matrix(int **m, int M)
{
for(int i = 0; i < M; i++)
delete []m[i];
delete []m;
}
int main()
{
int M = 5, N = 4;
int **m1 = create_matrix(M, N);
// fill matrix m1
int **m2 = create_matrix(N, M);
transpose(m1, m2, M, N);
delete_matrix(m1, M);
delete_matrix(m2, N);
return 0;
}
you provide a function return a pointer array which holds seperated memory blocks (each represents one row). then you must also provide the free (or delete) function at the same time, and in the same module (to ensure the memory managerment functions matches exactly).
int** transpose(int** matrix, int row, int column)
{
int** new_mat = new int*[column];
...
return new_mat;
}
//when free the mat, cols is not concerned;
void free_mat(int** matrix, int rows)
{
int i;
for(i= 0; i< rows; i++)
delete[] matrix[i];
delete[] matrix;
}
//use the function as:
int** m2 = transpose(m1, rows, cols);
...
free_mat(m2, cols);
//after free_mat(), m2 still holds the address.
//so make it nullptr.
m2 = NULL;
also you can allcate one plane continuous memory block to present 2-dimention matrix:
int* mat = new int[rows * cols];
//transfer mat[iRow][iCol] to mat[iRow * cols + iCol];
return mat;
I want to implement a Matrix class. I coded an array of arrays of pointers. When I set the values of each element of the array to 0 with a for loop, it works fine (apparently). But when I try to declare a function of my class (setvalues) to take the values of a 1D array and store them in the matrix, theres a problem with the arguments. I am not sure how to declare a function that takes a dynamic array as argument.
#include<iostream>
using namespace std;
class Matrix{
int rows, columns, numE;
double *mData=new double[numE];
public:
double** matrix;
Matrix(int,int);
setmatrix();
setvalues(double);
};
Matrix::Matrix(int x, int y){
rows=y;
columns=x;
matrix=new double*[columns];
for(int i = 0; i < columns; ++i){
matrix[i]=new double[rows];
}
}
Matrix::setmatrix(){
for(int i=0;i<rows;i++){
for(int j=0;j<columns;j++){
matrix[i][j]=0.0;
cout<<matrix[i][j]<<endl;
}
}
}
Matrix::setvalues(double mData[]){
for(int i=0;i<rows;i++){
for(int j=0;j<columns;j++){
matrix[i][j]=mData[i];
}
}
}
int main(){
Matrix AA(2,2);
AA.setmatrix();
//AA.setvalues();
for(int i=0;i<2;i++){
for(int j=0;j<2;j++){
cout<<AA.matrix[i][j] << endl;
}
}
cout<< AA.matrix << endl;
delete [] AA.matrix;
return 0;
}
PS: I don't want to use vector or smart pointers. Also if you have any feedback about my code regarding functionaity, readability and if you know a smarter way to do it please tell me.
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.
In my code I input the sizes of both dimensions and then declare a two-dimensional array. My question is, how do I use that array as a function parameter? I know that I need to write the number of columns in the function specification but how do I pass the number of columns?
void gameDisplay(gameCell p[][int &col],int a,int b) {
for(int i=0;i<a;i++) {
for(int j=0;j<b;j++) {
if(p[i][j].getStat()==closed)cout<<"C ";
if(p[i][j].getStat()==secure)cout<<"S ";
if(p[i][j].getBomb()==true&&p[i][j].getStat()==open)cout<<"% ";
if(p[i][j].getBomb()==false&&p[i][j].getStat()==open) {
if(p[i][j].getNum()==0)cout<<"0 ";
else cout<<p[i][j].getNum()<<" ";
}
cout<<endl;
}
}
}
int main() {
int row,col,m;
cout<<"Rows: ";cin>>row;cout<<"Columns: ";cin>>col;
m=row*col;
gameCell p[row][col];
gameConstruct(p[][col],m);
gameDisplay(p[][col],row,col);
}
I tried this way but it doesn't work.
Thank you.
In C++, you cannot have variable length arrays. That is, you can't take an input integer and use it as the size of an array, like so:
std::cin >> x;
int array[x];
(This will work in gcc but it is a non-portable extension)
But of course, it is possible to do something similar. The language feature that allows you to have dynamically sized arrays is dynamic allocation with new[]. You can do this:
std::cin >> x;
int* array = new int[x];
But note, array here is not an array type. It is a pointer type. If you want to dynamically allocate a two dimensional array, you have to do something like so:
std::cin >> x >> y;
int** array = new int*[x]; // First allocate an array of pointers
for (int i = 0; i < x; i++) {
array[i] = new int[y]; // Allocate each row of the 2D array
}
But again, this is still not an array type. It is now an int**, or a "pointer to pointer to int". If you want to pass this to a function, you will need the argument of the function to be int**. For example:
void func(int**);
func(array);
That will be fine. However, you almost always need to know the dimensions of the array inside the function. How can you do that? Just pass them as extra arguments!
void func(int**, int, int);
func(array, x, y);
This is of course one way to do it, but it's certainly not the idiomatic C++ way to do it. It has problems with safety, because its very easy to forget to delete everything. You have to manually manage the memory allocation. You will have to do this to avoid a memory leak:
for (int i = 0; i < x; i++) {
delete[] array[i];
}
delete[] array;
So forget everything I just told you. Make use of the standard library containers. You can easily use std::vector and have no concern for passing the dimensions:
void func(std::vector<std::vector<int>>);
std::cin >> x >> y;
std::vector<std::vector<int>> vec(x, std::vector<int>(y));
func(vec);
If you do end up dealing with array types instead of dynamically allocating your arrays, then you can get the dimensions of your array by defining a template function that takes a reference to an array:
template <int N, int M>
void func(int (&array)[N][M]);
The function will be instantiated for all different sizes of array that are passed to it. The template parameters (dimensions of the array) must be known at compile time.
I made a little program:
#include <iostream>
using namespace std;
void fun(int tab[][6], int first)
{}
int main(int argc, char *argv[])
{
int tab[5][6];
fun(tab, 5);
return 0;
}
In function definition you must put size of second index. Number of column is passed as argument.
I'm guessing from Problems with 'int' that you have followed the advices of the validated question and that you are using std::vector
Here is a function that returns the number of columns of an "array" (and 0 if there is a problem).
int num_column(const std::vector<std::vector<int> > & data){
if(data.size() == 0){
std::cout << "There is no row" << std::endl;
return 0;
}
int first_col_size = data[0].size();
for(auto row : data) {
if(row.size() != first_col_size){
std::cout << "All the columns don't have the same size" << std::endl;
return 0;
}
}
return first_col_size;
}
If you're using C-style arrays, you might want to make a reference in the parameter:
int (&array)[2][2]; // reference to 2-dimensional array
is this what you're looking for?
int* generate2DArray(int rowSize, int colSize)
{
int* array2D = new int[rowSize, colSize];
return array2D;
}
example . . .
#include <iostream>
#include <stdio.h>
int* generate2DArray(int rowSize, int colSize);
int random(int min, int max);
int main()
{
using namespace std;
int row, col;
cout << "Enter row, then colums:";
cin >> row >> col;
//fill array and display
int *ptr = generate2DArray(row, col);
for(int i=0; i<row; ++i)
for(int j=0; j<col; ++j)
{
ptr[i,j] = random(-50,50);
printf("[%i][%i]: %i\n", i, j, ptr[i,j]);
}
return 0;
}
int* generate2DArray(int rowSize, int colSize)
{
int* array2D = new int[rowSize, colSize];
return array2D;
}
int random(int min, int max)
{
return (rand() % (max+1)) + min;
}
instead of accessing p[i][j] you should access p[i*b + j] - this is actually what the compiler do for you since int[a][b] is flattened in the memory to an array in size of a*b
Also, you can change the prototype of the function to "void gameDisplay(gameCell p[],int a,int b)"
The fixed code:
void gameDisplay(gameCell p[],int a, int b) {
for(int i=0;i<a;i++) {
for(int j=0;j<b;j++) {
if(p[i*a +j].getStat()==closed)cout<<"C ";
if(p[i*a +j].getStat()==secure)cout<<"S ";
if(p[i*a +j].getBomb()==true&&p[i][j].getStat()==open)cout<<"% ";
if(p[i*a +j].getBomb()==false&&p[i][j].getStat()==open) {
if(p[i*a +j].getNum()==0)cout<<"0 ";
else cout<<p[i*a +j].getNum()<<" ";
}
cout<<endl;
}
}
}
int main() {
int row,col,m;
cout<<"Rows: ";cin>>row;cout<<"Columns: ";cin>>col;
m=row*col;
gameCell p[row][col];
gameConstruct(p[][col],m);
gameDisplay(p[],row,col);
}