How to allocate a matrix in C++? - c++

For a vector in C++, I have
class Vec
{
public:
int len;
double * vdata;
Vec();
Vec(Vec const & v)
{
cout<<"Vec copy constructor\n";
len = v.len;
vdata=new double[len];
for (int i=0;i<len;i++) vdata[i]=v.vdata[i];
};
I would greatly appreciate it if you could help me how to write an analogous code for a matrix. I am thinking something like this:
class Mat
{
public:
int nrows;
int ncols;
double * mdata;
Mat();
Mat(Mat const & m)
{
cout<<"Mat copy constructor\n";
nrows = m.nrows;
ncols = m.ncols;
But I don't know how to code the memory allocation for a matrix using the idea that first we put all the elements into a 1D array (row1 row2 ... rown) then we chop the array into rows and then chop each row into columns. Particularly, could you help me translate this idea into C++ language that is analogous to the following:
vdata=new double[len];
for (int i=0;i<len;i++) vdata[i]=v.vdata[i];
};
I am thinking of something like this:
double *data=new double[nrows*ncols];
for (int i=0;i<nrows;i++)
{
for (int j=0;j<ncols,j++){data(i,j)=m.mdata[i][j]};
};
But I am not sure about this part:
data(i,j)=m.mdata[i][j]
Also, I am supposed to use a pure virtual element indexing method: the (i,j) element of a Mat object m will be retrieved by m(i,j). I have to provide both const and non-const versions of this indexing operator.<-- May you show me how I could do this?
Thanks a lot.

Use as a single-dimensional array. You will notice that in practice, it's generally much simpler to use a 1d-array for such things.
class Matrix
{
public:
Matrix(unsigned int rows, unsigned int cols)
: _rows(rows)
, _cols(cols)
, _size(_rows*_cols)
, _components(new double[_size])
{
for(unsigned int i = 0; i < _size; ++i)
{
_components[i] = 0;
}
}
~Matrix()
{
delete[] _components;
}
double& operator()(unsigned int row, unsigned int col)
{
unsigned int index = row * _cols + col;
return _components[index];
}
private:
unsigned int _rows;
unsigned int _cols;
unsigned int _size;
double* _components;
};
However, if you want to actually use matrices and vectors, and not just implement them for learning, I would really advise you to use the Eigen library. It's free and open source and has great and easy-to-use vector and matrix classes.
While Eigen is great to use, if you want to look at source code of an existing implementation, it can be quite confusing for new programmers - it's very general and contains a lot of optimizations. A less complicated implementation of basic matrix and vector classes can be found in vmmlib.

Also you can use one standard vector to implement matrix but vector size will be nrows * ncols:
#include <vector>
class Mat {
public:
Mat(int rows, int cols):
nrows(rows),
ncols(cols),
elems(rows*cols,0)
{}
Mat(const Mat &m):
nrows(m.nrows),
ncols(m.ncols),
elems(m.elems.begin(), m.elems.end())
{}
double celem(int i,int j) const {
return elems[ncols*i + nrows*j];
}
double *pelem(int i,int j) {
return &elems[ncols*i + nrows*j];
}
private:
int nrows;
int ncols;
vector<double> elems;
};

Related

Initialise global array with respect to function input

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]();
}

Create a contiguous dynamic matrix

Arrays have this nice property of being contiguous blocks of memory. When using new to allocate memory for an array, it returns a pointer to a contiguous block of memory. However, if I allocate a matrix using new, like this:
#include <iostream> //std::cin
int main()
{
int n, m;
std::cin >> n >> m;
int** mat = new int*[n];
for (int i = 0; i < n; i++)
mat[i] = new int[m];
//use the matrix in some way
for (int i = 0; i < n; i++)
delete[] mat[i];
delete[] mat;
return 0;
}
This works, but mat doesn't point to a contiguous block of size n * m * sizeof(int). How can I do this in C++? I am just complying to the latest standard (that is C++17) and nothing else. I want an answer that doesn't involve STL containers or external libraries.
Please don't answer about C, as that is pretty easy to do in both C99 and C11 using variable-length arrays:
#include <stdio.h> //scanf
#include <stdlib.h> //malloc, free
int main()
{
int n, m;
scanf("%d %d", &n, &m);
//int mat[n][m]; VLA, but I want dynamic
int (*mat)[m] = malloc(n * sizeof *mat);
//use the matrix in some way;
free(mat);
return 0;
}
Here's what you were doing, almost exactly the same but without the non-contiguous memory:
#include <iostream> //std::cin
#include <memory>
int main()
{
int n, m;
std::cin >> n >> m;
auto matrix_data = std::make_unique<int[]>(n * m);
auto mat = std::make_unique<int[]>(n);
for(int i = 0; i < n; i++) { mat[i] = matrix_data.get() + i * m; }
// Use the matrix in some way
// No need to free anything - we're using smart pointers.
// No need to return 0 from main - that's the default
}
Notes:
This is still ugly code... you'd likely better create a proper matrix class, or better still - use somebody else's implementation.
It is better to follow #Someprogrammerdude's suggestion and use arithmetic rather than an array of pointers.
I kind of still don't know what particularly are you asking for. To store matrix elements in a contiguous location, simply allocate the memory for them as a one-dimensional dynamic array. The two basic options have been already discussed, either use a vector:
std::vector<int> mat(m * n);
or, if its memory overhead is significant for you, use a unique pointer:
auto mat = std::make_unique<int[]>(m * n);
Then, to access an element with i row index and j column index, simply use:
a_i_j = mat[i * n + j];
assuming m is the number of rows and n is the number of columns. This formula stores elements in so-called row-major order. If you need the column-major order, switch to:
a_i_j = mat[j * m + i];
Of course, whole approach would be much better encapsulated in a class with some getter operator mat(i, j);.
Here is a 2D matrix class that enables m[i][j] support and has a contiguous storage. It contains a minimalistic set of member functions to create and access elements.
It's a shame that the STD library does not provide such functionality. [i][j] element access is way less error prone than index arithmetics.
#include <cstddef>
#include <vector>
template <typename T>
class matrix
{
public:
using value_type = T;
private:
class row_view
{
public:
constexpr row_view(size_t length, value_type *begin)
: _length(length),
_begin(begin)
{}
value_type &operator[](size_t i) {
// TODO: check bounds
return *std::next(_begin, i);
}
const value_type &operator[](size_t i) const {
// TODO: check bounds
return *std::next(_begin, i);
}
size_t size() const {
return _length;
}
private:
size_t _length;
value_type *_begin;
};
public:
matrix(size_t rows, size_t cols, value_type &&defaultVal)
: _rows(rows),
_array(rows * cols, std::move(defaultVal))
{}
matrix(size_t rows, size_t cols)
: matrix(rows, cols, value_type{})
{}
size_t rows() const noexcept {
return _rows;
}
size_t cols() const noexcept {
return _array.size() / _rows;
}
auto operator[](size_t rowIndex) -> row_view{
const size_t offset = cols() * rowIndex;
return {cols(), &_array[offset]};
}
auto operator[](size_t rowIndex) const -> const row_view{
const size_t offset = cols() * rowIndex;
return {cols(), &_array[offset]};
}
private:
size_t _rows;
std::vector<value_type> _array;
};
https://godbolt.org/z/qoG6jGbh5

Create 2D array using size from parameters in C++

I am trying to create a simple 2D array with the size being the parameters passed by the method. In C# we would have something like this:
float[,] GenerateNoiseMap(int mapWidth, int mapHeight){
float noiseMap[,] = new float[mapWidth, mapHeight];
return noiseMap;
}
Any idea how I can create a 2D array and return it in C++?
So far the compiler gives me an error that the size has to be a constant value, and I want the values to be what the method parameters are
I like a simple wrapper around a 1D vector:
#include <vector>
class Matrix
{
private:
size_t rows, columns;
std::vector<double> matrix;
public:
Matrix(size_t numrows, size_t numcols) :
rows(numrows), columns(numcols), matrix(rows * columns)
{
}
double & operator()(size_t row, size_t column)
{
return matrix[row * columns + column]; // note 2D coordinates are flattened to 1D
}
double operator()(size_t row, size_t column) const
{
return matrix[row * columns + column];
}
size_t getRows() const
{
return rows;
}
size_t getColumns() const
{
return columns;
}
};
Documentation for std::vector
Usage:
Matrix noiseMap(mapWidth, mapHeight);
You cannot have a 2D C-like array with a dynamic size on both dimensions in C++. C# arrays look a bit like them, but they're not the same thing at all.
I recommend boost::multi_array for this:
#include <boost/multi_array.hpp>
boost::multi_array<float, 2> GenerateNoiseMap(int mapWidth, int mapHeight) {
return boost::multi_array<float, 2>{boost::extents[mapWidth][mapHeight]};
}
float ** create_matrix(size_t m, size_t n)
{
float ** answer = new float*[m];
for (size_t i =0; i < m; i++)
answer[i] = new float[n];
return answer;
}

C++ Class constructor 2d Array memory allocation

I took a programming class at university this semester, just out of curiosity. We're doing C++ and I enjoyed it a lot, but the last two weeks have been rather steep for me and heres what troubles my mind:
I'm given a class interface as follows:
class GameOfLife(int rows, int cols);
public:
GameOfLife();
void clear();
void set(int row, int col, int value);
void set(int row, int col, const char* values);
int get(int row, int col);
void print();
void advance();
};
First thing im being asked to do is to implement the constructor so that it allocates memory for a board with the amount of rows and cols passed in the argument. I thought i understood constructors but with this one I'm pretty lost.
After i declared int rows and cols in the private section i thought about something along the lines of
GameOfLife::GameOfLife(int x, int y){
rows = x;
cols = y;
board = new int* [rows];
But neither do i know how to handle the second dimension of the board without the compiler yelling at me nor do i know how to test if new memory is actually allocated properly.
Any help? :(
Thanks in advance!
In addition to thumbmunkey's correct answer, note that just because the external interface stipulates a 2D array doesn't mean the internal interface has to match.
You could have:
int* board = new int[rows * cols];
Where then instead of get() returning:
return board[x][y];
it would instead be:
return board[x * rows + y];
Sometimes one array is easier to think about than two. Sometimes it's not. Depends on how you want to do it (or if it's stipulated that you have to use one method or the other).
You have to allocate the column array for each row:
for(int i=0; i<rows; i++)
board[i] = new int [cols];
If the allocation fails (eg. when you're out of memory), you will get an exception.
What you are doing right now with board = new int* [rows];
Is allocating an array of integer pointers. You still need to allocate the memory for the actual integers which is what thumbmunkey is doing with,
for(int i=0;i<rows;i++)
board[i] = new int [cols];
There is already a class to dynamically manage memory, it's called vector. If you try to use new in your code then you end up having to reinvent the wheel and write dozens of lines of boilerplate that already exists inside vector.
Also it is simpler to store your board in a contiguous array, there is no need to use a bunch of separate memory blocks to hold the board.
Here is an example:
class GameOfLife
{
public:
GameOfLife(int rows, int cols);
void clear();
void set(int row, int col, int value);
void set(int row, int col, const char* values);
int get(int row, int col);
void print();
void advance();
private:
int rows, cols;
std::vector<int> values;
};
// In the cpp file
GameOfLife::GameOfLife(int rows, int cols)
: rows(rows), cols(cols), values(rows * cols) {}
void GameOfLife::set(int row, int col, int value)
{ values.at(row * cols + col) = value; }
int GameOfLife::get(int row, int col)
{ return values.at(row * cols + col); }
The essentials - constructor, destructor, getters:
class GameOfLife
{
public:
GameOfLife(int _rows, int _cols);
~GameOfLife ();
int GetRows () {return rows;}
int GetCols () {return cols;}
int **GetBoard () {return board;}
private:
int rows, cols;
int **board;
};
GameOfLife::GameOfLife(int _rows, int _cols)
{
rows = _rows;
cols = _cols;
board = new int *[rows];
for (int i = 0; i<rows; i++)
board[i] = new int[cols];
}
GameOfLife::~GameOfLife()
{
for (int i = 0; i<rows; i++)
delete [] board[i];
delete [] board;
}

How to create 2d array c++?

I need to create 2d array in c++.
I can't do it by int mas= new int[x][y]; or auto mas= new int[x][y];
I need to create an array dynamically like:
int x,y
auto mas= new int[x][y];//error - must be const.
Please help me.
int x,y;
x =3;
y = 5;
int ** mas = new int*[x];
for (int i=0;i<x;i++)
{
mas[i] = new int[y];
}
I think something like this.
Don't forget
for(int i=0;i<x;i++)
delete[] mas[i];
delete[] mas;
at the end.
The C++ tool for creating dynamically sized arrays is named std::vector. Vector is however one-dimensional, so to create a matrix a solution is to create a vector of vectors.
std::vector< std::vector<int> > mas(y, std::vector<int>(x));
It's not the most efficient solution because you pay for the ability to have each row of a different size. You you don't want to pay for this "feature" you have to write your own bidimensional matrix object. For example...
template<typename T>
struct Matrix
{
int rows, cols;
std::vector<T> data;
Matrix(int rows, int cols)
: rows(rows), cols(cols), data(rows*cols)
{ }
T& operator()(int row, int col)
{
return data[row*cols + col];
}
T operator()(int row, int col) const
{
return data[row*cols + col];
}
};
Then you can use it with
Matrix<int> mat(y, x);
for (int i=0; i<mat.rows; i++)
for (int j=0; j<mat.cols; j++)
mat(i, j) = (i == j) ? 1 : 0;
My advice would be to avoid the pain of multidimensional arrays in the first place and use a struct.
struct Point {
int x;
int y;
}
int points = 10;
Point myArray[points];
Then to access a value:
printf("x: %d, y: %d", myArray[2].x, myArray[2].y);
Depends on exactly what you're trying to achieve, though.
You can do the manipulations yourself.
int* mas = new int[x*y];
and access [i,j] by:
mas[i*y + j] = someInt;
otherInt = mas[i*y +j];
std::vector<std::vector<int> > mas(y, std::vector<int>(x));