What is the most efficient way to initialize a 3D vector? - c++

I have a 3D string vector in C++:
vector<vector<vector<string>>> some_vector
That I am trying is to find a fast method to allocate memory for it.
I tried to define it with two different methods as follow:
#include<vector>
#include<iostream>
#include<ctime>
using namespace std;
#define DIM1 100
#define DIM2 9
#define DIM3 120
int main()
{
clock_t t1_start = clock();
vector<vector<vector<string>>> vec1(DIM1, vector<vector<string>>(DIM2, vector<string>(DIM3)));
clock_t t1_end = clock();
double diff1 = (t1_end - t1_start) / double(CLOCKS_PER_SEC);
clock_t t2_start = clock();
vector<vector<vector<string>>> vec2;
vec2.resize(DIM1);
for(int i = 0; i < DIM1; i++)
{
vec2[i].resize(DIM2);
for(int j = 0; j < DIM2; j++)
vec2[i][j].resize(DIM3);
}
clock_t t2_end = clock();
double diff2 = (t2_end - t2_start) / double(CLOCKS_PER_SEC);
cout<<"1st definition used time: "<<diff1<<"s"<<endl;
cout<<"2nd definition used time: "<<diff2<<"s"<<endl;
}
I expect that the first method (vec1) could be faster than the 2nd one (vec2).
But it turned out that the 1st method is much slower than the 2nd. On my machine, the 1st method used 0.245 seconds, while the 2nd method used 0.152 seconds.
Moreover, when I switch the data type to int, the 1st one took 0.058 second, and the 2nd took 0.004.
May I know what cause such difference? And is there better way to allocate memory for a 3D vector?
Many thanks in advance.

May I know what cause such difference?
The first version constructs a 2-d vector by copying a 1-d vector, and then constructs the 3-d vector by copying that. This might be slower than resizing the vectors without copying. However, I'd hope that the difference would be negligible if you're building with optimisation.
And is there better way to allocate memory for a 3D vector?
It might be better to use a single contiguous array, wrapped in a class that provides multi-dimensional accessors. This would make allocation much simpler, and would also avoid some pointer dereferencing when accessing elements (at the cost of a bit of arithmetic). Something like this:
template <typename T>
class vector3d {
public:
vector3d(size_t d1=0, size_t d2=0, size_t d3=0, T const & t=T()) :
d1(d1), d2(d2), d3(d3), data(d1*d2*d3, t)
{}
T & operator()(size_t i, size_t j, size_t k) {
return data[i*d2*d3 + j*d3 + k];
}
T const & operator()(size_t i, size_t j, size_t k) const {
return data[i*d2*d3 + j*d3 + k];
}
private:
size_t d1,d2,d3;
std::vector<T> data;
};

I think I'd optimize it by allocating one large block of memory instead of a lot of little ones. This one is only 2D instead of 3D, but gives the basic idea:
template <class T>
class matrix {
size_t columns_;
std::vector<T> data;
public:
matrix(size_t columns, size_t rows) : columns_(columns), data(columns*rows) {}
T &operator()(size_t column, size_t row) { return data[row*columns_+column]; }
};
For 3D, you'll need to deal with "planes" (or something) along with rows and columns, but the basic idea is pretty much the same.

I added several features to Mike Seymour's code such as dynamically resize the 3d vector and on access/assign bounds checking for data vector.
template <typename T>
class vector3d
{
public:
vector3d(size_t d1=0, size_t d2=0, size_t d3=0, T const & t=T()) :
d1(d1), d2(d2), d3(d3), data(d1*d2*d3, t)
{}
T & operator()(size_t i, size_t j, size_t k)
{
return (i<=d1 && j<=d2 && k<=d3) ? data[i*d2*d3 + j*d3 + k]
: data.at(i*d2*d3 + j*d3 + k);
}
T const & operator()(size_t i, size_t j, size_t k) const
{
return data[i*d2*d3 + j*d3 + k];
}
void resize(const size_t _d1=0, const size_t _d2=0, const size_t _d3=0)
{
data.resize(_d1*_d2*_d3);
d1=_d1;
d2=_d2;
d3=_d3;
}
void shrink_to_fit()
{
data.shrink_to_fit();
}
const size_t length() const
{
return data.size();
}
const size_t capacity() const
{
return data.capacity();
}
const size_t x() const
{
return d1;
}
const size_t y() const
{
return d2;
}
const size_t z() const
{
return d3;
}
private:
size_t d1,d2,d3;
std::vector<T> data;
};
Usage:
vector3d<int> vec3d(2,2,2,31); //create 2x2x2 3d vector and fill it with 31
vec3d(1,1,2)=45; //assign 45 at vec3d(1,1,2)
vec3d.resize(2,2,1); //resize the vec3d to 2x2x1
vec3d(1,2,2)=67; //error (its out of bounds)

To initialize a 3D string vector you shall initialize the vector structure for each dimension one at a time and for each index, for instance:
vector<vector<vector<string> > > myvector; //declare the 3D vector
for(k=0; k<3; k++)
{
myvector.push_back(vector<vector<string> >()); //initialize the first index with a 2D vector
for(i=0; i<4; i++)
{
myvector[k].push_back(vector<string>()); //initialize the 2 index with a row of strings
for(j=0; j<4; j++)
{
result = " whatever you want to insert in the vector element";
myvector[k][i].push_back(result); //fulfill the last index regularly
}
}
}

When you initialize a vector of vectors in the first method, a temporary vector is allocated and then copied into the outer vector the required number of times. This means you have an extra allocation that is unnecessary and the new elements are initialized by copying their value from another data structure, which uses more memory accesses.
Resizing the vectors as per the second method is more ugly but avoids the extra allocation. Furthermore the new elements are created by the default constructor and do not need to copy from other vectors. This will also be faster.
If speed matters (and maybe it doesn't, premature optimization and all that), then you must use the second method (OR a single-block allocation as suggested by the other answers). I don't have faith that a compiler can simply "optimize" away the inefficiency of the first method.

Here is an example of various dimensions of vectors in case anyone out there cares. I know when I was starting out it was a pain to find how to give initial values to multidimension vectors as I couldn't find any examples;
// This simple project demonstrates a single vector, a 2D vector, a 3D vector and a 4D vector in C++
//
#include <iostream>
#include <vector>
using namespace std;
int main ()
{
vector<int> myVector = { 0,1,2,3,4,5,6 };
vector<vector<int>> my2dVector = { {1,2,3,4,5},{6,7,8,9,10},{11,12,13,14,15},{16,17,18,19,20},{21,22,23,24,25},{0,-1,-2,-3,-4},{-6,7,22,-15,-25},{true,true,false,true,false} };
vector < vector < vector<int>>> my3dVector =
{
{
{1,2,3},
{4,5,6}, // plane 0
{7,8,9}
},
{
{-1,-2,-3},
{-4,-5,-6}, // plane 1
{-10,-22,36}
},
{
{129,212,999},
{0,0,1}, // plane 2
{false,true,false}
}
};
vector<vector<vector<vector<int>>>> my4dVector =
{
{ //Cube 0
{
{1,2,3},
{4,5,6}, // plane 0
{7,8,9}
},
{
{-1,-2,-3},
{-4,-5,-6}, // plane 1
{-10,-22,36}
},
{
{129,212,999},
{0,0,1}, // plane 2
{false,true,false}
}
},
{ //Cube 1
{
{10,2,-9},
{44,55,60}, // plane 0
{71,85,99}
},
{
{-561,-6562,-453},
{-14,-55,-76}, // plane 1
{-110,-212,316}
},
{
{729,812,456},
{40,10,17}, // plane 2
{true,true,false}
}
}
};
// 1D VECTOR..............
cout << "This is a 1D vector of size " << myVector.size () << "\n";
for (int i = 0; i < myVector.size (); i++)
{
cout << myVector[i] << "\t";
}
cout << "\n\n";
// 2D VECTOR..............
cout << "This is a 2D vector of size " << my2dVector.size () << " X " << my2dVector[0].size () << ".";
if (my2dVector.size () == my2dVector[0].size ()) cout << " This is a square matrix.";
cout << "\n ";
for (int i = 0; i < my2dVector[0].size (); i++)
{
cout << "C" << i << "\t";
}
cout << endl;
for (int i = 0; i < my2dVector.size (); i++)
{
cout << "Row: " << i << " -> ";
for (int j = 0; j < my2dVector[i].size (); j++)
{
if (my2dVector[i][j] >= 0 && my2dVector[i][j] <= 9) cout << " ";
cout << my2dVector[i][j] << "\t";
}
cout << endl;
}
cout << "\n\n";
// 3D VECTOR.................
cout << "This is a 3D vector of size " << my3dVector[0].size () << " X " << my3dVector[0][0].size () << " with " << my3dVector.size () << " planes.\n";
for (int i = 0; i < my3dVector.size (); i++)
{
cout << "Plane #" << i << "\n";
for (int j = 0; j < my3dVector[i].size (); j++)
{
for (int k = 0; k < my3dVector[i][j].size (); k++)
{
cout << my3dVector[i][j][k] << "\t";
}
cout << "\n";
}
}
cout << "\n\n";
//4D VECTOR.................
cout << "This is a 4D vector of size " << my4dVector[0][0].size () << " X " << my4dVector[0][0][0].size () << " with " << my4dVector[0].size () << " planes and " << my4dVector.size () << " cubes.\n";
for (int i = 0; i < my4dVector.size (); i++)
{
cout << "\nCUBE #"<< i<< " _________________\n";
for (int j = 0; j < my4dVector[i].size (); j++)
{
cout << "Plane #" << j << " |\n";
for (int k = 0; k < my4dVector[i][j].size (); k++)
{
for (int l = 0; l < my4dVector[i][j][k].size (); l++)
{
cout << my4dVector[i][j][k][l] << "\t";
}
cout << "|\n";
}
cout << "________________________|\n";
}
cout << "\n";
}
}

Related

Operator overloading function is not working

I have a class Array this class has functions like set values to an array index or get a value of an array index, i wanted to make an overloading operator function to add two Arrays objects and the result is one array which every element is the sum of the same index elements of the other two arrays like:
Array A={1,4,6}, Array B={1,20,3} c=A+B //c={1+1,4+20,6+3}.
the problem is that in the Sum Array object i am getting some random values instead of the sum values ,i think they are some addresses cus my overloading function somehow is not working properly.
public:
Array(int asize)
:size(asize)
{
Arr = new int[size];
}
Array(const Array &other) {
size = other.size;
Arr = new int[other.size];//
for (int x = 0;x < other.size - 1;x++)
Arr[x] = other.Arr[x];
}
Array operator+(const Array &other) {
Array t(*this);// creating new array with the values of the left hand Array
int ssize = (other.size < size) ? other.size : size;//if the right hand array size is
for (int x = 0;x < ssize;x++) //smaller than the left side(choose the smallest size)
{
t.Arr[x] += other.Arr[x];
}
return t;
}
~Array() {
delete[] Arr;
}
int get(int index) {
return Arr[index];
}
void set(int index, int value) {
Arr[index] = value;
}
int getSize() {
return size;
}
Array operator+(const Array &rhs) {//I also tried without const and without & sign
Array H(this->getSize());
for (int i = 0;i < this->getSize();i++)
{
H.Arr[i] = rhs.get(i)+this->get(i);//or rhs.Arr[i]+this->Arr[i];
}
return H;
}
private:
int size;
int *Arr;
};
and this is my main function:
std::cout << "\n enter the size of the Array" << std::endl;
int Size1;
std::cin >> Size1;
Array A1(Size1);
std::cout << "insert the elements starting of the first element of the Array" << std::endl;
int E1;
for (int i = 0;i < Size1;i++) {
std::cout << "Element number" << i + 1 << " is: " << std::endl;
std::cin >> E1;
A1.set(i, E1);
}
std::cout << "\nenter the size of the Array 2" << std::endl;
int Size2;
std::cin >> Size2;
Array A2(Size2);
std::cout << "insert the elements starting of the first element of the Array" << std::endl;
int E2;
for (int i = 0;i < Size2;i++) {
std::cout << "Element number" << i + 1 << " is: " << std::endl;
std::cin >> E2;
A2.set(i, E2);
}
Array sum(2);// I am currently trying with only 2 elements Arrays just to check if its working
sum = A1 + A2;
for (int i = 0;i < Size2;i++) {
std::cout << sum.get(i) << " , ";
}
In addtion to the copyt constructor, please note
Array sum(2);// I am currently trying with only 2 elements Arrays just to check if its working
sum = A1 + A2;
This mean you need also operator= to be defined for your code to work properly.
BTW if you write: Array sum(A2 + A2); instead of those two lines, this will work also with no operator=.

Findmax() method returns second highest value when first element of array is the highest

This findMax function returns max value from the array only if it is located at some index other than first index. I don't understand why because my findMin function that has almost the same code works perfectly fine.
void findMax(int array[5])
{
maximum = array;
for (i = 0; i < 5; i++)
{
if (*(array+i) > *maximum)
*maximum = *(array+i);
}
cout<<"Maximum element in the array is "<< *maximum << "\n" ;
}
This is my findMin fun that is working fine.
void findMin(int array[5])
{
minimum = array;
for (i = 0; i < 5; i++)
{
if (*(array+i) < *minimum)
*minimum = *(array+i);
}
cout<<"Minimum element in the array is "<< *minimum <<"\n";
}
The other answers have described how to do this more cleanly in C++. But to point out the actual bug: it's in this line.
*maximum = *(array+i);
You're not reassigning the maximum pointer to point to the maximum element, but rather you're never changing the pointer, but changing the value inside the array where maximum points to (i.e. array[0]). You meant this instead:
maximum = array + i;
The same issue is present in your findMin function as well.
First of all, as one of the comments on your question said this is mostly C way of doing things. In C++ you should use std::vector, std::min_element and std::max_element. It's easier and safer to use them instead of doing everything manually by yourself.
But, if you really want to do it yourself, try this code out, it should work:
void findMax(int array[])
{
maximum = array;
for (int i = 1; i < 5; i++)
{
if (*(array + i) > *maximum)
maximum = (array + i);
}
cout << "Maximum element in the array is " << *maximum << "\n";
}
void findMin(int array[])
{
minimum = array;
for (int i = 1; i < 5; i++)
{
if (*(array + i) < *minimum)
minimum = (array + i);
}
cout << "Minimum element in the array is " << *minimum << "\n";
}
This should work assuming that minimum and maximum are globally declared like this:
int * maximum;
int * minimum;
There are minmax_element tools for finding maximum and minimum, this is the most optimal variant of solving your problem - see the definition of the StdMinMax function.
But if you want to implement the logic yourself, I gave an example of a function, see the definition of the MinMax function
#include <iostream>
#include <algorithm>
void StdMinMax(int* arr, const unsigned int size)
{
std::pair<int*, int*> bounds = std::minmax_element(arr, arr + size); // or use auto bounds = ... ore auto [max, min] = ...
std::cout << "min : " << *bounds.first << " max : " << *bounds.second << std::endl;
}
void MinMax(int* arr, const unsigned int size)
{
std::cout << "Find max : " << std::endl;
auto currentMax = *arr;
for (int i = 1 ; i < size; ++i)
{
if (arr[i] > currentMax)
{
currentMax = arr[i];
}
}
std::cout << "Max : " << currentMax << std::endl;
std::cout << "Find min : " << std::endl;
auto currentMin = *arr;
for (int i = 1 ; i < size; ++i)
{
if (arr[i] < currentMax)
{
currentMin = arr[i];
}
}
std::cout << "Min : " << currentMin << std::endl;
}
int main()
{
const unsigned int size{5};
int array[size]{1, 3, 4, -11, 77};
StdMinMax(array, size);
MinMax(array, size);
return 0;
}

Find dimensions of a container passed by reference

I wrote a following code:
#include <iostream>
#include <vector>
#include <iomanip>
using std::cin; using std::cout; using std::endl;
int DivideTwoFactorials(int m, int n)
{
int div(1);
while (m > n)
{
div *= m;
m--;
}
return div;
}
int Factorial(int m)
{
int fact(1);
for (int i(1); i <=m; i++) fact *= i;
return fact;
}
int BinomialCoefficient(int m, int n)
{
return (DivideTwoFactorials(m, n) * (1./Factorial(m-n)));
}
template <typename Type>
void Modify3DContainer(Type &a, int fun(int, int), int p = 0, int q = 0)
{
int m(a.size());
int n(a[0].size());
int z(a[0][0].size());
for (int i(0); i < m; i++)
{
for (int j(0); j < n; j++)
{
for (int k(0); k < z; k++)
{
if (a[i][j][k] == fun(p, q)) a[i][j][k] = a[i][j][k] * a[i][j][k];
}
}
}
}
int main()
{
cout << endl << "Input dimensions of 3D container: ";
int m, n, p;
cin >> m >> n >> p;
std::vector<std::vector<std::vector<int>>> a(m, std::vector<std::vector<int>>(n, std::vector<int>(p)));
cout << endl << "Input elements of 3D container: ";
int x;
for (int i(0); i < m; i++)
{
for (int j(0); j < n; j++)
{
for (int k(0); k < p; k++)
{
cin >> x;
a[i][j][k] = x;
}
}
}
Modify3DContainer(a, BinomialCoefficient, 6, 4);
cout << endl << "Modified 3D container: " << endl << endl;
for (int i(0); i < m; i++)
{
for (int j(0); j < n; j++)
{
for (int k(0); k < p; k++)
{
cout << std::setw(6) << a[i][j][k];
}
cout << endl;
}
cout << endl;
}
return 0;
}
There is one issue regarding the function "Modify3DContainer" which accepts the following parameters:
a reference on a 3D container
a function that returns an int and receives two int parameters
two int parameters with default value 0.
The function is supposed to find all elements in the 3D container that are equal to return value of function defined by the second parameter when that function receives p and q as parameters, and substitute those elements with their square value.
The problem here is that function "Modify3DContainer" accepts multiple types of containers and I am not allowed to pass dimensions of the container to said function (c++ programming assignment). The function currently works only for vector of vectors of vectors by using the size() method, but it will not work for regular arrays. I tried using the sizeof operator, but it doesn't work on multidimensional vectors. Checking the type of the container with typeid could be one possible solution, but there are many combinations to check since the 3D container could, for example, be vector of vectors of deques etc.
So my question is, is there a way to find the size of passed 3D container, no matter its type?
Thank you.
If you really want to know the size then what you are looking for is std::size. It will tell you the size of anything passed to it that is a raw array or an object that has a size member function. Unfortunately it is a C++17 feature so you might not have it available in the compiler you are using.
Fortunately the mechanics for it already exist in the current standard so we can write our own like the possible implementation provided at previous link
template <class C>
constexpr auto size(const C& c) -> decltype(c.size())
{
return c.size();
}
template <class T, std::size_t N>
constexpr auto size(const T (&array)[N]) noexcept
{
return N;
}
And using them in something like
int main()
{
std::vector<std::vector<std::vector<int>>> vec(10, std::vector<std::vector<int>>(20, std::vector<int>(30, 0)));
int arr[10][20][30];
std::cout << size(vec) << "\t" << size(arr) << "\n";
std::cout << size(vec[0]) << "\t" << size(arr[0]) << "\n";
std::cout << size(vec[0][0]) << "\t" << size(arr[0][0]) << "\n";
return 0;
}
We get
10 10
20 20
30 30
Live Example
If you do not need the size but just need to loop then you can use a range based for loop or a regular loop and use std::begin and std::end which works with containers and arrays.

operator overloading [][] 2d array c++

I have a 2D array and I want to define a function that returns the value of the index that the user gives me using operator overloading.
In other words:
void MyMatrix::ReturnValue()
{
int row = 0, col = 0;
cout << "Return Value From the last Matrix" << endl;
cout << "----------------------------------" << endl;
cout << "Please Enter the index: [" << row << "][" << col << "] =" << ((*this).matrix)[row][col] << endl;
}
The operation ((*this).matrix)[row][col] should return an int.
I have no idea how to build the operator [][].
Alternatively, I could concatenate a couple of calls to the operator [], but I didn't succeed in it, because the first call to that operaror will return int* and the second one will return int, and it compel to build another operator, and I dont want to do that.
The data matrix is defined like
int** matrix; matrix = new int*[row];
if (matrix == NULL)
{
cout << "Allocation memory - Failed";
}
for (int i = 0; i < row; i++)//Allocation memory
{
matrix[i] = new int[col];
if (matrix[i] == NULL)
{
cout << "Allocation memory - Failed";
return;
}
}
What can I do?
Thank you,
Simply, such an operator does not exist, so you can not overload it.
A possible solution is to define two classes: the Matrix and the Row.
You can define the operator[] of a Matrix so that it returns a Row, then define the same operator for the Row so that it returns an actual value (int or whatever you want, your Matrix could be also a template).
This way, the statement myMatrix[row][col] will be legal and meaningful.
The same can be done in order to assign a new Row to a Matrix or to change a value in a Row.
* EDIT *
As suggested in the comments, also you should take in consideration to use operator() instead of operator[] for such a case.
This way, there wouldn't be anymore the need for a Row class too.
You can define your own operator [] for the class. A straightforward approach can look the following way
#include <iostream>
#include <iomanip>
struct A
{
enum { Rows = 3, Cols = 4 };
int matrix[Rows][Cols];
int ( & operator []( size_t i ) )[Cols]
{
return matrix[i];
}
};
int main()
{
A a;
for ( size_t i = 0; i < a.Rows; i++ )
{
for ( size_t j = 0; j < a.Cols; j++ ) a[i][j] = a.Cols * i + j;
}
for ( size_t i = 0; i < a.Rows; i++ )
{
for ( size_t j = 0; j < a.Cols; j++ ) std::cout << std::setw( 2 ) << a[i][j] << ' ';
std::cout << std::endl;
}
}
The program output is
0 1 2 3
4 5 6 7
8 9 10 11
I have no idea how to build the operator [][].
Sometimes it is fine to use a different operator, namely ():
int& Matrix::operator () (int x, int y)
{
return matrix[x][y];
}
const int& Matrix::operator () (int x, int y) const
{
return matrix[x][y];
}
int diagonal (const Matrix& m, int x)
{
return m (x, x); // Usage.
}
Advantage:
No need to use "intermediate" class like Row or Column.
Better control than with Row& Matrix operator (int); where someone could use the Row reference to drop in a row of, say, illegal length. If Matrix should represent a rectangular thing (image, matrix in Algebra) that's a potential source of error.
Might be less tedious in higher dimensions, because operator[] needs classes for all lower dimensions.
Disadvantage:
Uncommon, different syntax.
No more easy replacement of complete rows / columns, if that's desired. However, replacing columns is not easy, anyway, provided you used rows to model (and vice versa).
In either case, there are pros and cons if the number of dimensions are not known at runtime.
I was looking for self-tested array replacement...
Improved version returns reference or NULL reference and checks boundaries inside.
#include <iostream>
#include <iomanip>
template<typename T, int cols>
class Arr1
{
public:
Arr1(T (&place)[cols]) : me(place) {};
const size_t &Cols = cols;
T &operator [](size_t i)
{
if (i < cols && this != NULL) return me[i];
else {
printf("Out of bounds !\n");
T *crash = NULL;
return *crash;
}
}
private:
T (&me)[cols];
};
template<typename T, int rows, int cols>
class Arr2
{
public:
const size_t &Rows = rows;
const size_t &Cols = cols;
Arr2() {
ret = NULL;
for (size_t i = 0; i < rows; i++) // demo - fill member array
{
for (size_t j = 0; j < cols; j++) matrix[i][j] = cols * i + j;
}
}
~Arr2() {
if (ret) delete ret;
}
Arr1<T, cols>(&operator [](size_t i))
{
if (ret != NULL) delete ret;
if (i < rows) {
ret = new Arr1<T, cols>(matrix[i]);
return *ret;
}
else {
ret = NULL;
printf("Out of bounds !\n");
return *ret;
}
}
//T(&MemberCheck)[rows][cols] = matrix;
private:
T matrix[rows][cols];
Arr1<T, cols> *ret;
};
template<typename T,int rows, int cols>
class Arr
{
public:
const size_t &Rows = rows;
const size_t &Cols = cols;
T(&operator [](size_t i))[cols]
{
if (i < rows) return matrix[i];
else {
printf("Out of bounds !\n");
T(*crash)[cols] = NULL;
return *crash;
}
}
T (&MemberCheck)[rows][cols] = matrix;
private:
T matrix[rows][cols];
};
void main2()
{
std::cout << "Single object version:" << endl;
Arr<int, 3, 4> a;
for (size_t i = 0; i <= a.Rows; i++)
{
int *x = &a[i][0];
if (!x) printf("Fill loop - %i out of bounds...\n", i);
else for (size_t j = 0; j < a.Cols; j++) a[i][j] = a.Cols * i + j;
}
for (size_t i = 0; i < a.Rows; i++)
{
for (size_t j = 0; j <= a.Cols; j++) {
std::cout << std::setw(2) << a[i][j] << ' ';
if (a.MemberCheck[i][j] != a[i][j])
printf("Internal error !");
}
std::cout << std::endl;
}
std::cout << endl << "Double object version:" << endl;
Arr2<int, 3, 4> a2;
for (size_t i = 0; i < a2.Rows; i++)
{
for (size_t j = 0; j <= a2.Cols; j++) {
int &x = a2[i][j];
if (&x)
{
x++;
std::cout << std::setw(2) << a2[i][j] << ' ';
//if (&a2.MemberCheck[i][j] != &a2[i][j])
// printf("Internal error !");
}
}
}
}
Output
Single object version:
Out of bounds !
Fill loop - 3 out of bounds...
0 1 2 3 4
4 5 6 7 8
8 9 10 11 -858993460
Double object version:
1 2 3 4 Out of bounds !
5 6 7 8 Out of bounds !
9 10 11 12 Out of bounds !
it works fine in the program below
#include<iostream>
using namespace std;
class A{
public:
int r,c;
int** val;
A()
{
r=0;c=0;val=NULL;
}
A(int row,int col)
{
r=row;c=col;
int count=0;
val=new int*[row];
for(int i=0;i<r;i++){
val[i]=new int[col];
for(int j=0;j<c;j++){
count++;
val[i][j]=count;
}
}
}
int* &operator[](int index){
return val[index];
}
};
int main(void){
A a(3,3);
cout<<a[1][2];
return 0;
}
here, a[1][2] first computes a[1]-->which returns 2nd row as (int*) type
then it's read as (int*)[2] which returns 3rd element of that row.In short,
a[1][2]------>(a[1])[2]------>(val[1])[2]------>val[1][2].

Vector of Vectors to create matrix

I am trying to take in an input for the dimensions of a 2D matrix. And then use user input to fill in this matrix. The way I tried doing this is via vectors (vectors of vectors). But I have encountered some errors whenever I try to read in data and append it to the matrix.
//cin>>CC; cin>>RR; already done
vector<vector<int> > matrix;
for(int i = 0; i<RR; i++)
{
for(int j = 0; j<CC; j++)
{
cout<<"Enter the number for Matrix 1";
cin>>matrix[i][j];
}
}
Whenever I try to do this, it gives me a subscript out of range error. Any advice?
You have to initialize the vector of vectors to the appropriate size before accessing any elements. You can do it like this:
// assumes using std::vector for brevity
vector<vector<int>> matrix(RR, vector<int>(CC));
This creates a vector of RR size CC vectors, filled with 0.
As it is, both dimensions of your vector are 0.
Instead, initialize the vector as this:
vector<vector<int> > matrix(RR);
for ( int i = 0 ; i < RR ; i++ )
matrix[i].resize(CC);
This will give you a matrix of dimensions RR * CC with all elements set to 0.
I'm not familiar with c++, but a quick look at the documentation suggests that this should work:
//cin>>CC; cin>>RR; already done
vector<vector<int> > matrix;
for(int i = 0; i<RR; i++)
{
vector<int> myvector;
for(int j = 0; j<CC; j++)
{
int tempVal = 0;
cout<<"Enter the number for Matrix 1";
cin>>tempVal;
myvector.push_back(tempVal);
}
matrix.push_back(myvector);
}
Assume we have the following class:
#include <vector>
class Matrix {
private:
std::vector<std::vector<int>> data;
};
First of all I would like suggest you to implement a default constructor:
#include <vector>
class Matrix {
public:
Matrix(): data({}) {}
private:
std::vector<std::vector<int>> data;
};
At this time we can create Matrix instance as follows:
Matrix one;
The next strategic step is to implement a Reset method, which takes two integer parameters that specify the new number of rows and columns of the matrix, respectively:
#include <vector>
class Matrix {
public:
Matrix(): data({}) {}
Matrix(const int &rows, const int &cols) {
Reset(rows, cols);
}
void Reset(const int &rows, const int &cols) {
if (rows == 0 || cols == 0) {
data.assign(0, std::vector<int>(0));
} else {
data.assign(rows, std::vector<int>(cols));
}
}
private:
std::vector<std::vector<int>> data;
};
At this time the Reset method changes the dimensions of the 2D-matrix to the given ones and resets all its elements. Let me show you a bit later why we may need this.
Well, we can create and initialize our matrix:
Matrix two(3, 5);
Lets add info methods for our matrix:
#include <vector>
class Matrix {
public:
Matrix(): data({}) {}
Matrix(const int &rows, const int &cols) {
Reset(rows, cols);
}
void Reset(const int &rows, const int &cols) {
data.resize(rows);
for (int i = 0; i < rows; ++i) {
data.at(i).resize(cols);
}
}
int GetNumRows() const {
return data.size();
}
int GetNumColumns() const {
if (GetNumRows() > 0) {
return data[0].size();
}
return 0;
}
private:
std::vector<std::vector<int>> data;
};
At this time we can get some trivial matrix debug info:
#include <iostream>
void MatrixInfo(const Matrix& m) {
std::cout << "{ \"rows\": " << m.GetNumRows()
<< ", \"cols\": " << m.GetNumColumns() << " }" << std::endl;
}
int main() {
Matrix three(3, 4);
MatrixInfo(three);
}
The second class method we need at this time is At. A sort of getter for our private data:
#include <vector>
class Matrix {
public:
Matrix(): data({}) {}
Matrix(const int &rows, const int &cols) {
Reset(rows, cols);
}
void Reset(const int &rows, const int &cols) {
data.resize(rows);
for (int i = 0; i < rows; ++i) {
data.at(i).resize(cols);
}
}
int At(const int &row, const int &col) const {
return data.at(row).at(col);
}
int& At(const int &row, const int &col) {
return data.at(row).at(col);
}
int GetNumRows() const {
return data.size();
}
int GetNumColumns() const {
if (GetNumRows() > 0) {
return data[0].size();
}
return 0;
}
private:
std::vector<std::vector<int>> data;
};
The constant At method takes the row number and column number and returns the value in the corresponding matrix cell:
#include <iostream>
int main() {
Matrix three(3, 4);
std::cout << three.At(1, 2); // 0 at this time
}
The second, non-constant At method with the same parameters returns a reference to the value in the corresponding matrix cell:
#include <iostream>
int main() {
Matrix three(3, 4);
three.At(1, 2) = 8;
std::cout << three.At(1, 2); // 8
}
Finally lets implement >> operator:
#include <iostream>
std::istream& operator>>(std::istream& stream, Matrix &matrix) {
int row = 0, col = 0;
stream >> row >> col;
matrix.Reset(row, col);
for (int r = 0; r < row; ++r) {
for (int c = 0; c < col; ++c) {
stream >> matrix.At(r, c);
}
}
return stream;
}
And test it:
#include <iostream>
int main() {
Matrix four; // An empty matrix
MatrixInfo(four);
// Example output:
//
// { "rows": 0, "cols": 0 }
std::cin >> four;
// Example input
//
// 2 3
// 4 -1 10
// 8 7 13
MatrixInfo(four);
// Example output:
//
// { "rows": 2, "cols": 3 }
}
Feel free to add out of range check. I hope this example helps you :)
try this. m = row, n = col
vector<vector<int>> matrix(m, vector<int>(n));
for(i = 0;i < m; i++)
{
for(j = 0; j < n; j++)
{
cin >> matrix[i][j];
}
cout << endl;
}
cout << "::matrix::" << endl;
for(i = 0; i < m; i++)
{
for(j = 0; j < n; j++)
{
cout << matrix[i][j] << " ";
}
cout << endl;
}
Vector needs to be initialized before using it as cin>>v[i][j]. Even if it was 1D vector, it still needs an initialization, see this link
After initialization there will be no errors, see this link
What you have initialized is a vector of vectors, so you definitely have to include a vector to be inserted("Pushed" in the terminology of vectors) in the original vector you have named matrix in your example.
One more thing, you cannot directly insert values in the vector using the operator "cin". Use a variable which takes input and then insert the same in the vector.
Please try this out :
int num;
for(int i=0; i<RR; i++){
vector<int>inter_mat; //Intermediate matrix to help insert(push) contents of whole row at a time
for(int j=0; j<CC; j++){
cin>>num; //Extra variable in helping push our number to vector
vin.push_back(num); //Inserting numbers in a row, one by one
}
v.push_back(vin); //Inserting the whole row at once to original 2D matrix
}
I did this class for that purpose. it produces a variable size matrix ( expandable) when more items are added
'''
#pragma once
#include<vector>
#include<iostream>
#include<iomanip>
using namespace std;
template <class T>class Matrix
{
public:
Matrix() = default;
bool AddItem(unsigned r, unsigned c, T value)
{
if (r >= Rows_count)
{
Rows.resize(r + 1);
Rows_count = r + 1;
}
else
{
Rows.resize(Rows_count);
}
if (c >= Columns_Count )
{
for (std::vector<T>& row : Rows)
{
row.resize(c + 1);
}
Columns_Count = c + 1;
}
else
{
for (std::vector<T>& row : Rows)
{
row.resize(Columns_Count);
}
}
if (r < Rows.size())
if (c < static_cast<std::vector<T>>(Rows.at(r)).size())
{
(Rows.at(r)).at(c) = value;
}
else
{
cout << Rows.at(r).size() << " greater than " << c << endl;
}
else
cout << "ERROR" << endl;
return true;
}
void Show()
{
std::cout << "*****************"<<std::endl;
for (std::vector<T> r : Rows)
{
for (auto& c : r)
std::cout << " " <<setw(5)<< c;
std::cout << std::endl;
}
std::cout << "*****************" << std::endl;
}
void Show(size_t n)
{
std::cout << "*****************" << std::endl;
for (std::vector<T> r : Rows)
{
for (auto& c : r)
std::cout << " " << setw(n) << c;
std::cout << std::endl;
}
std::cout << "*****************" << std::endl;
}
// ~Matrix();
public:
std::vector<std::vector<T>> Rows;
unsigned Rows_count;
unsigned Columns_Count;
};
'''