c++ matrix insert value using iterators (homework) - c++

I'm pretty new to C++ and got an assignment to make a matrix using only STL containers. I've used a vector (rows) of vectors (columns). The problem I'm having is in the 'write' operation - for which I may only use an iterator-based implementation. Problem is, quite simply: it writes nothing.
I've tested with a matrix filled with different values, and while the iterator ends up on exactly the right spot, it doesn't change the value.
Here's my code:
void write(matrix mat, int row, int col, int input)
{
assert(row>=0 && col>=0);
assert(row<=mat.R && col<=mat.C);
//I set up the iterators.
vector<vector<int> >::iterator rowit;
vector<int>::iterator colit;
rowit = mat.rows.begin();
//I go to the row.
for(int i = 0; i<row-1; ++i)
{
++rowit;
}
colit = rowit->begin();
//I go to the column.
for(int j = 0; j<col-1; ++j)
{
++colit;
}
*colit = input; //Does nothing.
}
What am I overlooking?
Thanks.

matrix mat is a parameter by value, it copies the matrix and hence you are writing to a copy.
You should pass the matrix by reference instead, like matrix & mat.
But wait... You are passing the matrix every time as the first parameter, this is a bad sign!
This usually indicates that the parameter should be turned into an object on which you can run the methods; that way, you don't need to pass the parameter at all. So, create a Matrix class instead.
Please note that there is std::vector::operator[].
So, you could just do it like this:
void write(matrix & mat, int row, int col, int input)
{
assert(row>=0 && col>=0);
assert(row<=mat.R && col<=mat.C);
mat[row][col] = input;
}

Related

Use only one column of array as function argument

Suppose I have a very large array of data:
double matrix[100000][100] = {0.0};
During runtime this data is updated. Now I want to give the reference to this data to a function FUNC. However, I want to only give one column to the function FUNC, like:
FUNC(matrix["all elements"]["only column with index 5"]);
and not the entire array. Furthermore, I dont want to perform a copy operation before (because this is slow), I just want to give the pointer or reference to the specific rows/columns inside the large array data. The function should only see an array like:
void FUNC(double* array)
{
for (int i = 0; i < 100000; i++)
doSomething(array[i]);
}
How do I do give this partial data from array "matrix" to the function FUNC?
The column values of your matrix are not sequential in memory, so you can't pass a single column to FUNC() without making a copy of the data into a sequential array. However, if you are able to add the column index as an additional parameter to FUNC() then you can do something like this instead:
const int MAX_ROWS = ...;
const int MAX_COLS = ...;
using Matrix = double[MAX_ROWS][MAX_COLS];
void doSomething(double value)
{
...
}
void FUNC(const Matrix& matrix, int column)
{
for (int row = 0; row < MAX_ROWS; ++row) {
doSomething(matrix[row][column]);
}
}
Matrix matrix = {};
...
FUNC(matrix, 5);
Online Demo

Is it possible to pass a variable length array as a parameter in C++?

I do not know the value of V before. It is found within a file I open in the program. It cannot be defined as such #DEFINE V __. It does not work as a global variable. The input file changes V based on the contents. Expected the parameters to pass and use the djisktra's algorithm found on Geeks for Geeks.
I have tried declaring V globally, but I am given an error saying "variable must have constant value."
void dijkstra(int graph[V][V], int src, int V)
//array function being pasted, error is the V in graph[V]
//V is defined at beginning of main as
int V;
//where V is changed
while(std::getline(file2,newstr))
{
if(newstr.find(check) != std::string::npos)
{
V++;
}
}
//where it is passed in main
for(int i = 0; i < V; i++)
{
size = V;
dijkstra(array[size][size], i, V);
}
Don't use C-style arrays. Use std::vector and friends from the Standard Library where you can ask for the size if you want to know.
Converted:
void dijkstra(const std::vector<std::vector<int>>& graph, int src) {
auto v = graph.size();
// ... Other code.
}
For inserting you can use push_back:
std::vector<std::vector<int>> graph;
while(std::getline(file2,newstr)) {
if(newstr.find(check) != std::string::npos) {
std::vector<int> row;
row.push_back(...);
graph.push_back(row);
}
}
Then pass it in like a regular variable:
dijkstra(graph, src);
If all that vector stuff looks really ugly, typedef it to something more friendly looking.
For c style arrays, you need to know the size at compile time. A variable like int N; is a runtime value. A variable like constexpr int N = 9; is usable at compile time and cannot be mutated.
If you need an array sizeable at runtime, you need some sort of dynamic array. The most common one is std::vector.
void dijkstra(std::vector<int> graph, int src, int V)
std::vector<int> graph;
graph.resize(V * V); // vector are resizable
for(int i = 0; i < V; i++)
{
size = V;
dijkstra(graph, i, V);
}
Is it possible to pass a variable length array as a parameter in C++.
No.
Variable length arrays are not supported in std C++, But read on, they have an alternative that is surprisingly better.
I do not know the value of V before it is found within a file I open
in the program.
A 1d vector is trivial to create, after your code has found V, no compile time constant required.
Early in the startup in one of my programs, the gBoard vector is built using argv[3] and argv[4]. Here is a snippet:
aTermPFN += argv[1]; // ouput tty, /dev/pts/<argv[1]>
fillPatternChoiceLetter = argv[2][0];
aMaxRow = stoi(argv[3]);
aMaxCol = stoi(argv[4]);
userDim = true;
Clearly, the program has already started ... and V size is easily computed from (aMaxRow * aMaxCol).
I find it easy to access a 1d vector (or 1d array), in row major order, as if it is a 2d matrix, with the following function:
// game-board-index: computes index into the single dimension vector
// from 2d (row, col) matrix coordinates
size_t gbIndx(int r, int c) { return static_cast<size_t>((r * maxCol) + c); }
// a 2d game board of cells
// 2d access (row major order) implemented using 1d access
Cell_t* getCell( int r, int c ) { return (gBoard [gbIndx(r,c)]); }
// 1d access is surprisingly convenient for many functions
Cell_t* getCell( uint gbIndex ) { return (gBoard [gbIndex]); }
Sample initialization usage:
// vvvvvvvvvvvvvvvvvvv_-- 2d matrix access
gBoard [ gbIndx((midRow+1), midCol) ] -> setOptionX();
// ^^^^^^--1d row-major order index
A randomized gGoard is trivial in 1d:
void GOLUtil_t::setRandom()
{
CellVec_t myVec(gBoard); // copy cell vector
random_device rd;
mt19937_64 gen(rd());
shuffle (myVec.begin(), myVec.end(), gen); // shuffle order
int count = 1;
for ( auto it : myVec ) // randomly mark half the cells
{
if(count++ & 1)
it->setAlive(); // every odd cell
}
}
Note from https://en.cppreference.com/w/cpp/container/vector:
"The elements are stored contiguously, which means that elements can be accessed not only through iterators, but also using offsets to regular pointers to elements. This means that a pointer to an element of a vector may be passed to any function that expects a pointer to an element of an array."
I was surprised how often the 1d access enabled simpler code.
for (auto it : gBoard)
it->init(); // command each cell to init
Summary:
Despite variable-length-arrays (vla) not being supported in std C++, I believe you will find std::vector a better alternative. And you will find that passing the vector within your code works.

C++ Avoiding Triple Pointers

I am trying to create an array of X pointers referencing matrices of dimensions Y by 16. Is there any way to accomplish this in C++ without the use of triple pointers?
Edit: Adding some context for the problem.
There are a number of geometries on the screen, each with a transform that has been flattened to a 1x16 array. Each snapshot represents the transforms for each of number of components. So the matrix dimensions are 16 by num_components by num_snapshots , where the latter two dimensions are known at run-time. In the end, we have many geometries with motion applied.
I'm creating a function that takes a triple pointer argument, though I cannot use triple pointers in my situation. What other ways can I pass this data (possibly via multiple arguments)? Worst case, I thought about flattening this entire 3D matrix to an array, though it seems like a sloppy thing to do. Any better suggestions?
What I have now:
function(..., double ***snapshot_transforms, ...)
What I want to accomplish:
function (..., <1+ non-triple pointer parameters>, ...)
Below isn't the function I'm creating that takes the triple pointer, but shows what the data is all about.
static double ***snapshot_transforms_function (int num_snapshots, int num_geometries)
{
double component_transform[16];
double ***snapshot_transforms = new double**[num_snapshots];
for (int i = 0; i < num_snapshots; i++)
{
snapshot_transforms[i] = new double*[num_geometries];
for (int j = 0; j < num_geometries; j++)
{
snapshot_transforms[i][j] = new double[16];
// 4x4 transform put into a 1x16 array with dummy values for each component for each snapshot
for (int k = 0; k < 16; k++)
snapshot_transforms[i][j][k] = k;
}
}
return snapshot_transforms;
}
Edit2: I cannot create new classes, nor use C++ features like std, as the exposed function prototype in the header file is getting put into a wrapper (that doesn't know how to interpret triple pointers) for translation to other languages.
Edit3: After everyone's input in the comments, I think going with a flattened array is probably the best solution. I was hoping there would be some way to split this triple pointer and organize this complex data across multiple data pieces neatly using simple data types including single pointers. Though I don't think there is a pretty way of doing this given my caveats here. I appreciate everyone's help =)
It is easier, better, and less error prone to use an std::vector. You are using C++ and not C after all. I replaced all of the C-style array pointers with vectors. The typedef doublecube makes it so that you don't have to type vector<vector<vector<double>>> over and over again. Other than that the code basically stays the same as what you had.
If you don't actually need dummy values I would remove that innermost k loop completely. reserve will reserve the memory space that you need for the real data.
#include <vector>
using std::vector; // so we can just call it "vector"
typedef vector<vector<vector<double>>> doublecube;
static doublecube snapshot_transforms_function (int num_snapshots, int num_geometries)
{
// I deleted component_transform. It was never used
doublecube snapshot_transforms;
snapshot_transforms.reserve(num_snapshots);
for (int i = 0; i < num_snapshots; i++)
{
snapshot_transforms.at(i).reserve(num_geometries);
for (int j = 0; j < num_geometries; j++)
{
snapshot_transforms.at(i).at(j).reserve(16);
// 4x4 transform put into a 1x16 array with dummy values for each component for each snapshot
for (int k = 0; k < 16; k++)
snapshot_transforms.at(i).at(j).at(k) = k;
}
}
return snapshot_transforms;
}
Adding a little bit of object-orientation usually makes the code easier to manage -- for example, here's some code that creates an array of 100 Matrix objects with varying numbers of rows per Matrix. (You could vary the number of columns in each Matrix too if you wanted to, but I left them at 16):
#include <vector>
#include <memory> // for shared_ptr (not strictly necessary, but used in main() to avoid unnecessarily copying of Matrix objects)
/** Represents a (numRows x numCols) 2D matrix of doubles */
class Matrix
{
public:
// constructor
Matrix(int numRows = 0, int numCols = 0)
: _numRows(numRows)
, _numCols(numCols)
{
_values.resize(_numRows*_numCols);
std::fill(_values.begin(), _values.end(), 0.0f);
}
// copy constructor
Matrix(const Matrix & rhs)
: _numRows(rhs._numRows)
, _numCols(rhs._numCols)
{
_values.resize(_numRows*_numCols);
std::fill(_values.begin(), _values.end(), 0.0f);
}
/** Returns the value at (row/col) */
double get(int row, int col) const {return _values[(row*_numCols)+col];}
/** Sets the value at (row/col) to the specified value */
double set(int row, int col, double val) {return _values[(row*_numCols)+col] = val;}
/** Assignment operator */
Matrix & operator = (const Matrix & rhs)
{
_numRows = rhs._numRows;
_numCols = rhs._numCols;
_values = rhs._values;
return *this;
}
private:
int _numRows;
int _numCols;
std::vector<double> _values;
};
int main(int, char **)
{
const int numCols = 16;
std::vector< std::shared_ptr<Matrix> > matrixList;
for (int i=0; i<100; i++) matrixList.push_back(std::make_shared<Matrix>(i, numCols));
return 0;
}

Inserting values to a multidimensional-vector in C++

I've got a minor problem.
I'm using multidimensional-vectors and I want to insert some values to it at a given position. I'm making a sudoku in wxWidgets and i'm getting the tiles the player have put in and wanting to store them in my mVector.
The mVector looks like this.
vector< vector<string> > board{9, vector<string>(9)};
And at first i've added values just like this.
board[row][col] = value;
"value" is a string and row/col are ints.
Is this a legit way of adding values to the mVector? I'm asking this because when I update the board, by doing this above, I for some reason can't run my other functions where i'm solving the board, giving a hint to the board and so on. Before i store the new values to it all the functions works correkt. Do I maby need to use some other type of build in functions for the vector like insert, push_back or something instead?
Since you declared the vector as size 9x9, yes that is a valid way of assigning values.
Otherwise you could declare the board as
vector<vector<string>> board;
Then fill it with
for (int i = 0; i < 9; ++i)
{
vector<string> row;
for (int j = 0; j < 9; ++j)
{
row.push_back(value); // where value is whatever you want
}
board.push_back(row);
}
But again, once the board is of size 9x9, you can simply assign a value at any cell for example
board[2][4] = "hello";
Working example

Parentheses followed by parentheses

I am trying to understand what a piece of C++ code is doing, but know nothing about C.
I have a loop like this:
(_A[0])=eigenMatrix::Zero(_n, _n);
for(i=0; i<_n; i++){
for(j=0; j<=i; j++) (_A[0])(j,i)=(_A[0])(i,j)=value[i*n+j];
}
A is a vector of eigenMatrix type: vector <#eigenMatrix> _A;
I think the first line is defining (_A[0]) as a zero n*n matrix, but I can't work out what the (_A[0])(j,i) part is doing, and can't find any reference to this kind of ()() phrase in c++.
Operator Overloading
In C++ you can respecify the meaning of various operators. For a Matrix class, it does make sense to define a meaning for parentheses:
double & Matrix::operator()(int row, int col) {
return data[row][col];
}
would result in a Matrix object _A[0] from which elements can be obtained as in _A[0](2, 2).
lvalue Assignment
An interesting detail in your example is the assignment to an lvalue -- you can see _A[0](j,i) is on the left-hand side. Such an assignment is possible because we return a reference (double &) to the inner representation data.
If you open the header file that provides you with eigenMatrix (or rather its base class), you will find a declaration of a reference (&) returned by some Matrix::operator() method.
Why bother?
It provides convenient access to matrix elements while at the same time providing more control than simply exposing the inner data directly. For example you could imagine checks like
double & Matrix::operator()(int row, int col) {
assert((row >= 0) && (row < n_row) && (col >=0 ) && (col < n_col));
return data[row][col];
}
I am not sure why () are used around _A[0].
_A[0](i,j) probably just returns a reference to value in i-th row and j-th column or another way around.
Here you can see how this operator is used:
int main()
{
MatrixXd m(2,2);
m(0,0) = 3;
m(1,0) = 2.5;
m(0,1) = -1;
m(1,1) = m(1,0) + m(0,1);
}
and just to make everythign clear that's how you declare such an object.
class Matrix
{
private:
float value[4][4];
public:
float& operator()(int i, int j)
{
return value[i][j];
}
};
Lets break down this code.
so lets assume that this line:
(_A[0])=eigenMatrix::Zero(_n, _n);
is actually
A = eigen::Matrix::Zero(_n, _n);
I am making this assumption because
Only element 0 of _A is ever accessed.
I think maybe you are using the eigen Library.
The next part is then a little easier.
for(i=0; i<_n; i++){ // Loop from 0 to `_n` which is the size of the Zero Matrix.
for(j=0; j<=i; j++) // Loop from 0 to i, this means you are only accessing the
// lower left side of the matrix.
i=0 -> [j=0, ... No Access
i=1 -> [j=0, j=1, ... No Access
i=_n -> [j=0, j=1, ... j=_n
(A)(j,i) = (A)(i,j) = value[i*n+j];
The first part is redundant, you are assigning to yourself.
The second part ( = value[...]) is assigning the currently looked at matrix element to the same element but in a 2D array stored as a 1D vector called value.
}