Related
I am learning C++ with experiencein mostly Python, R and SQL.
The way arrays (and vectors which differes somehow from 1d-arrays? and matrices which are 2d-arrays?) work in C++ seems quite different as I cannot specify the size of dimension of the array with an argument from the function.
A toy-example of my goal is some thing like this:
Have a function my_2d_array which takes two arguments M and N and returns a matrix or 2d-array of dimension (MxN) with elements indicating the position of that element. E.g. calling my_2d_array(4,3) would return:
[[00, 01, 02],
[10, 11, 12],
[20, 21, 22],
[30, 31, 32]]
The main function should execute my_2d_array and be able to potentially perform calculations with the result or modify it.
This is my attempt (with errors):
int my_2d_array(int N, int M) {
int A[N][M];
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
std::string element = std::to_string(i) + std::to_string(j);
A[i][j] = element;
}
}
return A;
}
void main() {
int N, M;
N = 4;
M = 3;
int A[N][M] = my_2d_array(N, M);
// Print the array A
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
std::cout << A[i][j] << " ";
}
std::cout << "\n";
}
}
One (1) dimensional attempt of #JustLearning's suggestion:
int my_array(int N) {
std::array<int, N> A;
for (int i = 0; i < N; i++) {
A[i] = i;
}
return A;
}
int main() {
int N = 4;
int A[N] = my_array(N);
// Print the array A
for (int i = 0; i < N; i++) {
std::cout << A[i] << " ";
}
}
You can use a 2d vector like this
vector<vector int> A;
It works the same way as a 2d array
Welcome to C++! Your function my_2d_array has a couple of issues:
the return type is int, however you are attempting to return an array of ints.
the identifier of an array in C++ is actually a pointer to the first element of that array. Therefore, when you return A, you must be aware of how it should be passed to a new variable in the main part of the code. In particular, your code is passing a reference to a temporary variable A, which is not permitted or safe.
In addition, in C++, unless you know what you're doing, main should always return an int:
int main() { ... }
What is not clear from your question is whether you are attempting to implement your own "array" class, or simply want to use arrays already established in the standard. For the latter, std::array is a good place to start. The advantage is that you can return std::arrays from functions like you return ints or doubles.
std::arrays are good if you plan to work with arrays of fixed size, as the size becomes part of the type: std::array<int, 3> my_array;. Then you can fill it in manually or with member functions of the class (see dox linked above).
If for some reason you prefer to work with arrays of dynamical size (sizes that will change during running your program), std::vector is the way to go.
Finally, if you are actually learning C++ by attempting to implement a container MyArray, you should specify that in your question and be a bit more specific in what help you need.
Here's a working example in 1d:
#include <iostream>
#include <array>
template <int N>
std::array<int, N> my_array() {
std::array<int, N> A;
for (int i = 0; i < N; i++) {
A[i] = i;
}
return A;
}
int main() {
const int N = 4;
std::array<int, N> arr = my_array<N>();
// Print the array A
for (int i = 0; i < N; i++) {
std::cout << arr[i] << " ";
}
}
Since the size of a std::array is included it its type, you need to create a function template, which is basically a function that works for different types. (In C++, std::array<int, 3> and std::array<int, 4> are considered different types.)
In order to use this in main, the index is promoted to a const int, as plain ints can vary during run time, and therefore are not suitable for defining types. (In C++ jargon, look up constant expressions).
Finally, note that both the return type and the type of the variable that receives the value returned by the function must be std::array, not int as you tried in your 1d code.
Following your comment, I can see why you are confused in your attempts to use a matrix in code.
There are many types of containers in C++. Many of them you can find in the standard library (std::vector, std::list, std::set, ...), others you can create yourself or use other libraries. Plain arrays (like int a[5]) are a somewhat unique case because they come from C and are part of the language itself.
A plain array lives on the stack (not very important but you might want to read up on stack vs heap allocations), and refers to a contiguous region of memory.
If you declare some array a like int a[5], you get a region of 5 integers one after the other, and you can point to the first one by just writing a. You can access each of them using a[i] or, equivalently, *(a+i).
If you declare a like int a[5][3], you now get a region of 15 integers, but you can access them slightly differently, like a[i][j], which is equivalent to *(a+i*3+j).
The important thing to you here is that the sizes (5 and 3) must be compile-time constants, and you cannot change them at runtime.
The same is true for std::array: you could declare a like std::array<std::array<int, 3, 5> a and get a similar region of 15 integers, that you can access the same way, but with some convenience (for example you can return that type, whereas you cannot return a plain array type, only a pointer, losing the size information in the process).
My advice is not to think of these arrays as having dimensionality, but as simple containers that give you some memory to work with however you choose. You can very well declare a like std::array<int, 15> a and access elements in a 2D way by indexing like this: a[i*3+j]. Memory-wise, it's the same.
Now, if you want the ability to set the sizes at runtime, you can use std::vector in a similar way. Either you declare a like std::vector<std::vector<int>> a(5, std::vector<int>(3)) and deal with the nested vectors (that initialization creates 5 std::vector<int> of size 3 each), or you declare a as a single vector like std::vector<int> a(15) and index it like a[i*3+j]. You can even make your own class that wraps a vector and helps with the indexing.
Either way, it's rare in C++ to need a plain array, and you should generally use some kind of container, with std::vector being a good choice for a lot of things.
Here is an example of how your code would look like using vectors:
#include <vector>
#include <string>
#include <iostream>
std::vector<std::string> my_2d_array(int N, int M) {
std::vector<std::string> A(N*M);
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
std::string element = std::to_string(i) + std::to_string(j);
A[i*M+j] = element;
}
}
return A;
}
int main() {
int N, M;
N = 4;
M = 3;
std::vector<std::string> A = my_2d_array(N, M);
// Print the array A
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
std::cout << A[i*M+j] << " ";
}
std::cout << "\n";
}
}
And here is a very crude example of a Matrix class used to wrap the vectors:
#include <vector>
#include <string>
#include <iostream>
template<typename T>
class Matrix {
public:
Matrix(int rowCount, int columnCount) : v(rowCount*columnCount), columnCount(columnCount) {}
T& operator()(int row, int column) {
return v[row*columnCount + column];
}
private:
std::vector<T> v;
int columnCount;
};
Matrix<std::string> my_2d_array(int N, int M) {
Matrix<std::string> A(N, M);
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
std::string element = std::to_string(i) + std::to_string(j);
A(i, j) = element;
}
}
return A;
}
int main() {
int N, M;
N = 4;
M = 3;
Matrix<std::string> A = my_2d_array(N, M);
// Print the array A
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
std::cout << A(i, j) << " ";
}
std::cout << "\n";
}
}
I have the following problem:
I've a precomputed 2d matrix of values which i need to lookup very often and compute only once
The size of the matrix is about 4000x4000 at most
The matrix won't be sparse, i typically need almost all values.
The values in the matrix can be boolean, integer or double. At least they are always small objects
Currently i am storing the precomputed values in a std::vector<<std::vector<T>>, and i've noticed the lookups into this datastructure takes quite some time in heavy computations. I've googled around and so far the suggested implementation seems to be to try a solution in which all the memory is stored contigious using an 1D array where the location in this array is computed based on i and j.
Does anybody have a good example implementation of this or has an even better suggestion? I couldn't find a modern C++ example, while it seems to be a very common problem to me. I'd prefer to use someone elses code instead of reinventing the wheel here. Of course i will measure the differences to see whether it actually improves performance.
Examples i've found:
https://medium.com/#patdhlk/c-2d-array-a-different-better-solution-6d371363ebf8
https://secure.eld.leidenuniv.nl/~moene/Home/tips/matrix2d/
Here is a very simple and efficient 2-d matrix. The 'main' creates a 10000x10000 double array 'mat', then filled it with random number. The array 'mat' is copied into another array 'mat2'. your may input two integers 'n' and 'm' between 0 and 9999 to fetch the double data at mat2(n,m).
Feel free to use or test it. Let me know if you encounter problems or need some more functions to be implemented. Good luck!
#ifndef ytlu_simple_matrix_class_
#define ytlu_simple_matrix_class_
#include <iostream>
#include <iomanip>
#include <complex>
template <typename T> class tMatrix
{
public:
T *ptr;
int col, row, size;
inline T* begin() const {return ptr;}
inline T* end() const {return this->ptr + this->size;}
inline T operator()(const int i, const int j) const { return ptr[i*col+j];
} // r-value
inline T&operator()(const int i, const int j) { return ptr[i*col+j]; } //l-value
inline tMatrix(): col{0}, row{0}, size{0}, ptr{0} {;}
tMatrix(const int i, const int j): col(j), row(i), size(i*j)
{
ptr = new T [this->size] ;
}
tMatrix(const tMatrix<T>&a) : tMatrix<T>(a.row, a.col)
{
std::copy(a.begin(), a.end(), this->ptr);
}
tMatrix<T>& operator=(tMatrix<T>&&a)
{
this->col = a.col;
this->row = a.row;
delete [] this->ptr;
this->ptr = a.ptr;
a.ptr = nullptr;
return *this;
}
tMatrix<T>& operator=(const tMatrix<T>&a)
{
if (col==a.cpl && row==a.row) std::copy(a.begin(), a.end(), this->ptr);
else { tMatrix<T>&&v(a); *this = std::move(v);}
return *this;
}
~tMatrix() {delete [] this->ptr;}
}; //end of class tMatrix
template <typename X> std::ostream& operator<<(std::ostream&p, const tMatrix<X>&a)
{
p << std::fixed;
for (int i=0; i<a.row; i++) {
for (int j=0; j <a.col; j++) p << std::setw(12) << a(i, j);
p << std::endl;
}
return p;
}
using iMatrix = tMatrix<int>;
using rMatrix = tMatrix<double>;
using cMatrix = tMatrix<std::complex<double> >;
#endif
//
//
#include <ctime>
#include <cstdlib>
#define N1 10000
int main()
{
int n, m;
std:srand(time(NULL)); // randomize
rMatrix mat(N1, N1); // declare a 10000 x 10000 double matrix
//
// fill the whole matrix with double random number 0.0 - 1.0
//
for (int i = 0; i<mat.row; i++)
{ for (int j=0; j<mat.col; j++) mat(i, j) = (double)std::rand() / (double)RAND_MAX; }
//
// copy mat to mat 2 just for test
//
rMatrix mat2 = mat;
//
// fetch data test input 0 <= n m < 10000 to print mat2(n, m)
//
while(1)
{
std::cout << "Fetch 2d array at (n m) = ";
std::cin >> n >> m;
if ((n < 0) || (m < 0) || (n > mat2.row) || (m > mat2.col) )break;
std::cout << "mat(" << n << ", " << m << ") = " << mat2(n, m) << std::endl << std::endl;
}
return 0;
}
The compile parameter I used and the test run. It takes a couple seconds to fill the random numbers, and I felt no lapse at all in fetch a data running in my aged PC.
ytlu#ytlu-PC MINGW32 /d/ytlu/working/cpptest
$ g++ -O3 -s mtx_class.cpp -o a.exe
ytlu#ytlu-PC MINGW32 /d/ytlu/working/cpptest
$ ./a.exe
Fetch 2d array at (n m) = 7000 9950
mat(7000, 9950) = 0.638447
Fetch 2d array at (n m) = 2904 5678
mat(2904, 5678) = 0.655934
Fetch 2d array at (n m) = -3 4
I am trying to find an efficient and proper way to fill a 2D std::array matrix with an enum value. I am doing this:
#include <iostream>
#include <array>
template<class T, size_t ROW, size_t COL>
using Matrix = std::array<std::array<T, COL>, ROW>;
enum class State { FREE = 0, BUSY, BLOCKED, RESERVED };
int main() {
const int mapX = 4;
const int mapY = 9;
// create a 5x10 2D array
Matrix<State, mapY, mapX> MapMatrix;
// fill array with State::RESERVED value
for (int y = 0; y <= mapY; y++) MapMatrix[y].fill(State::RESERVED);
std::cout << "MapMatrix contains:\n";
for (int y = 0; y <= mapY; ++y) {
for (int x = 0; x <= mapX; ++x) {
std::cout << static_cast<int>(MapMatrix[x][y]) << " ";
}
std::cout << std::endl;
}
return 0;
}
Is the for loop I am doing the best way to fill the matrix with the enum value? Is there a way to fill the matrix during the declaration of Matrix<State, mapY, mapX> MapMatrix (like a constructor)?
Thanks!
You can't fill it on initialization unless you are filling it with zeros, or you specify every element explicitly. If you rearranged your enum so that RESERVED is zero, then you could initialize it like this:
Matrix<State, mapY, mapX> MapMatrix = {};
If you can't do that, then yes, a for loop is probably the best option. Keep it simple. But you have a few problems. First, your comment says that you are creating a 5x10 array, but you are not. You are creating a 4x9 array. If you want to create a 5x10 array, then you need to pass 5 and 10 as your template parameters. I think you're probably getting confused by the fact that the last element of an array of size N is N - 1. This off-by-one issue is only relevant to accessing elements of an array, not in specifying the size of an array.
Second, you are iterating past the end of your array, because your loop condition is y <= mapY, rather than y < mapY. But it would be better if you just used a range-for loop.
for (auto& arr : MapMatrix)
arr.fill(State::RESERVED);
I think that a loop based initialization is a good solution.
But, just for fun, I propose you another solution std::index_sequence and template pack expansion based.
A working example (with index corrected)
#include <iostream>
#include <utility>
#include <array>
template <typename T, std::size_t ROW, std::size_t COL>
using Matrix = std::array<std::array<T, COL>, ROW>;
enum class State { FREE = 0, BUSY, BLOCKED, RESERVED };
template <typename T, std::size_t ... Rs, std::size_t ... Cl>
Matrix<T, sizeof...(Rs), sizeof...(Cl)> initMat
(T const & tVal,
std::index_sequence<Rs...> const &,
std::index_sequence<Cl...> const &)
{
auto col = std::array<T, sizeof...(Cl)>{ { ((void)Cl, tVal)... } };
return Matrix<T, sizeof...(Rs), sizeof...(Cl)>
{ { ((void)Rs, col)... } };
}
int main()
{
constexpr std::size_t mapX = 5U;
constexpr std::size_t mapY = 10U;
// create a 5x10 2D array
auto MapMatrix = initMat(State::RESERVED,
std::make_index_sequence<mapX>(),
std::make_index_sequence<mapY>());
std::cout << "MapMatrix contains:\n";
for ( auto y = 0U ; y < mapY ; ++y )
{
for ( auto x = 0U ; x < mapX ; ++x )
std::cout << static_cast<int>(MapMatrix[x][y]) << " ";
std::cout << std::endl;
}
return 0;
}
I am trying to get an understanding of how to work with matrices in C++. The code at the bottom is supposed to take an input matrix and return the places where there are 0s. However, I am getting the following errors:
matrix.cpp:47:3: error: no matching function for call to 'make_zero' make_zero(i,j,l);
^~~~~~~~~
matrix.cpp:8:6: note: candidate function not viable: no known conversion from 'double [i][j]' to
'double (*)[col]' for 3rd argument
void make_zero(int row, int col, double matrix[row][col])
^
1 error generated.
when I try to run the following code:
// Matrix
#include <iostream>
#include <stdio.h>
using namespace std;
void make_zero(int row, int col, double matrix[row][col])
{
int k,l;
for(k=0;k<row;k++)
for(l=0;l<col;l++)
{
if(matrix[k][l]==0)
printf("%d %d\n",k,l);
}
}
int main ()
{
int i = 0,j = 0;
cout << "Enter no of rows of the matrix";
cin >> i;
cout << "Enter no of columns of the matrix";
cin >> j;
double l[i][j];
int p = 0, q = 0;
while (p < i) {
while (q < j) {
cout << "Enter the" << p + 1 << "*" << q + 1 << "entry";
cin >> l[p][q];
q = q + 1;
}
p = p + 1;
q = 0;
}
cout << l << "\n";
make_zero(i,j,l);
}
Any help would be appreciated. Thanks.
There are a bunch of ways to do this with pointers. The most common is
void make_zero(int row, int col, double ** matrix)
defines a pointer (usually rows) to a pointer (usually columns). Unfortunately
double l[i][j];
does not define a pointer to a pointer. If this syntax is supported by the compiler, and the compiler is not required to allow arrays of variable length, it most likely defines a pointer to a 1D array (double l[i*j];) and hides the indexing arithmetic used to convert the array to two dimensions. Anyway, it can't be passed to a double ** because it isn't a double **
Trying to pass as an array is troublesome
void make_zero(int row, int col, double matrix[][NUMBER_OF_COLUMNS])
The number of columns in the array must be known to perform the indexing arithmetic and be provided to any functions called with it. This means that number of columns cannot be changed at run time because the indexing used by the function will be rendered invalid.
Getting around this would require changes to the compiler that will drive it further and further from the C++ standard. A bad idea since there are a number of simple ways around calling functions with multi dimensional arrays. Most depend on arrays of arrays or std::vectors of std::vectors.
And when it comes to these solutions, as far as I'm concerned, the best is don't. I'm not going to cover them.
None of the arrays representing a dimension are guaranteed to be anywhere close to the others in memory, and this limits the CPU's ability to read and cache. Without caching and being able to look ahead, a modern CPU is at a serious performance disadvantage. (Read for more information: Why is it faster to process a sorted array than an unsorted array?)
So what you want is a 1 D array, and those are easy to pass around. The indexing math is also easy, row number * size of column + column number, but you need to pass at least the size of the column around. Rather than scatter the book-keeping around like this:
void make_zero(int row, int col, std::vector<double> matrix)
make a wrapper class like this:
class Matrix
{
private:
std::vector<double> myArray;
size_t nrRows;
size_t nrColumns;
public:
Matrix(size_t rows, size_t columns) :
myArray(rows * columns), // allocate vector to store matrix.
nrRows(rows),
nrColumns(columns)
{
}
size_t getNrRows() const
{
return nrRows;
}
size_t getNrColumns() const
{
return nrColumns;
}
// gets value at row, column and returns a reference so caller can
// modify the value
double& operator()(size_t row, size_t column)
{
// note: No sanity check for row >= nrRows or column > nrColumns
return myArray[row * nrColumns + column];
}
// gets value at row, column and returns a copy so caller cannot
// change the contents of the Matrix
double operator()(size_t row, size_t column) const
{
return myArray[row * nrColumns + column];
}
};
Using the vector gets around a number of common pointer-to-array problems by managing its own memory. No destructor is required and Matrix can be copied and moved without requiring special handling because vector performs all that heavy lifting for us.
And as a usage example, let's make a function that prints the matrix out:
std::ostream & operator<<(std::ostream & out, const Matrix & in)
{
for (size_t i = 0; i < in.getNrRows(); i++)
{
for (size_t j = 0; j < in.getNrColumns(); j++)
{
out << in(i,j) << ' ';
}
out << "\n";
}
return out;
}
And modifying OP's main function to use Matrix we get:
int main()
{
int i = 0, j = 0;
cout << "Enter no of rows of the matrix";
cin >> i;
cout << "Enter no of columns of the matrix";
cin >> j;
Matrix matrix(i,j);
int p = 0, q = 0;
while (p < i)
{
while (q < j)
{
cout << "Enter the" << p + 1 << "*" << q + 1 << "entry";
cin >> matrix(p,q);
q = q + 1;
}
p = p + 1;
q = 0;
}
cout << matrix << "\n";
make_zero(matrix);
}
void make_zero(int row, int col, double ** matrix)
Note, that you need to pass also size of the matrix separately.
Also you can use
std::vector<std::vector<double> >
instead and pass this object by reference, pointer, or just make a copy.
Actually, it works, but your problem in this line also:
double l[i][j];
i, j is unknown during the compile time.
You have 2 ways.
1) dynamically allocate the memory
2) use std::vector<std::vector<double> >. Default constructor already sets zero values. But you can do it manually like this:
#include <iostream>
#include <vector>
void make_zero(std::vector<std::vector<double> > & to_zero) {
for (int i = 0; i < to_zero.size(); ++i) {
for (int j = 0; j < to_zero[i].size(); ++j) {
to_zero[i][j] = 0;
}
}
}
void print_double_vector(const std::vector<std::vector<double> > & to_print) {
for (int i = 0; i < to_print.size(); ++i) {
for (int j = 0; j < to_print[i].size(); ++j) {
std::cout << to_print[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
int main() {
// your code goes here
int n, m;
std::cin >> n >> m;
std::vector<std::vector<double> > d(n, std::vector<double>(m));
print_double_vector(d);
make_zero(d);
print_double_vector(d);
return 0;
}
http://ideone.com/0X53Yj
I have a matrix of values (stored as an array of values) and a vector with the matrix dimensions( dims[d0, d1, d2]).
I need to build a string like that:
"matA(j, k, l) = x;"
where j, k, l are the indices of the matrix and x the value of the element. I need to write this for each value of the matrix and for matrices with 2 to n dimensions.
I have a problem isolating the base case and replicating it in a useful way. I did a version in a switch case with a case for each dimension and a number of for cycles equal to the number of dimensions:
for (unsigned int k=1; k<=(dims[2]); k++)
{
for (unsigned int j=1; j<=(dims[1]); j++)
{
for (unsigned int i=1; i<=(dims[0]); i++)
{
strs << matName << "(" << i << "," << j << ","<< k << ")="<< tmp[t]<< "; ";
....
but is not what I wanted.. Any idea for a more general case with a variable number of dimensions?
You need a separate worker function to recursively generate the series of indices and main function which operates on it.
For example something like
void worker(stringstream& strs, int[] dims, int dims_size, int step) {
if (step < dims_size) {
... // Add dims[step] to stringstream. Another if may be necessary for
... // whether include `,` or not
worker(strs, dims, dims_size, step + 1);
} else {
... // Add cell value to stringstream.
}
}
string create_matrix_string(int[] dims, int dims_size, int* matrix) {
... // Create stringstream, etc.
strs << ... // Add matrix name etc.
worker(strs, dims, dims_size, 0);
strs << ... // Add ending `;` etc.
}
The main problem here is the value, since the dimension is not known during compilation. You can avoid that by encoding matrix in single-dimensional table (well, that's what C++ is doing anyway for static multidimensional tables) and call it using manually computed index, eg. i + i * j (for two-dimensional table). You can do it, again, by passing an accumulated value recursively and using it in final step (which I omitted in example above). And you probably have to pass two of them (running sum of polynomial components, and the i * j * k * ... * x product for indices from steps done so far.
So, the code above is far from completion (and cleanliness), but I hope the idea is clear.
You can solve this, by doing i, j and k in a container of the size of dim[] - sample:
#include <iostream>
#include <vector>
template< typename Itr >
bool increment( std::vector< int >& ijk, Itr idim, int start )
{
for( auto i = begin(ijk); i != end(ijk); ++i, ++idim )
{
if( ++*i <= *idim )
return true;
*i = start;
}
return false;
}
int main()
{
using namespace std;
int dim[] = { 5, 7, 2, 3 };
const int start = 1;
vector< int > ijk( sizeof(dim)/sizeof(*dim), start );
for( bool inc_done = true; inc_done
; inc_done = increment( ijk, begin(dim), start ) )
{
// .. here make what you want to make with ijk
cout << "(";
bool first = true;
for( auto j = begin(ijk); j != end(ijk); ++j )
{
if( !first )
cout << ",";
else
first = false;
cout << *j;
}
cout << ")= tmp[t] " << endl;
}
return 0;
}