I have 2 2D arrays that represent a maze
const char maze1[10][11]
and
const char maze2[20][21]
I'm trying to create 1 function to handle both mazes like so:
void solveMaze(maze[][])
{
}
and just pass the maze like solveMaze(maze1);
However, I have to supply a size for the array, which is different depending on which maze is being passed in. Without overloading the function or using function templates, how can I have 1 function to handle both arrays?
C++ answer
Use std::vector:
// Initialize the vector with 11 rows of 10 characters
std::vector<std::vector<char> > maze(11, std::vector<char>(10));
void solveMaze(const std::vector<std::vector<char> > &maze) {
// note that you can access an element as maze[x][y]
}
The boost::multi_array is slightly more efficient (if you're allowed to use boost). I think it goes something like this:
boost::multi_array<char, 2> maze(boost::extents[10][11]);
void solveMaze(const boost::multi_array<char, 2> &maze) {
// note that you can access an element as maze[x][y]
}
C answer
Use pointers:
const char maze1[10][11];
void solveMaze(char *maze, size_t x_length, size_t y_length) {
// note that you can access an element as maze[x + (x_length * y)]
}
Std c++ doesn't allow variably sized arrays. Gnu extensions allow this.
given a gnu compiler, you can
void solvemaze(int w, int h, const char maze[h][w])
{ //solve it...
}
otherwise,
void solvemaze(int w, int h, const char *maze)
{ //solve it, bearing in mind:
//maze[y][x] = maze[(w*y)+x];
}
Actually it can be solved without vector:
template<size_t N, size_t M>
void foo(char (&maze)[N][M])
{
// do your stuff here
}
On the other hand, I would also prefer to use vectors: it just feels safer.
Related
The following code compiles with gcc but not g++. Is it possible to write a function with a matrix argument of arbitrary dimensions in C++?
void print_mat(const int nr, const int nc, const float x[nr][nc]);
#include <stdio.h>
void print_mat(const int nr, const int nc, const float x[nr][nc])
{
for (int ir=0; ir<nr; ir++) {
for (int ic=0; ic<nc; ic++) {
printf(" %f",x[ir][ic]);
}
printf("\n");
}
}
To build on Peter’s answer, you can use the single-dimension variant with proper indexing to do the work. But you can make invoking the function much nicer in C++:
void print_mat(const int nr, const int nc, const float *x)
{
...
}
template <std::size_t NumRows, std::size_t NumColumns>
void print_mat(const float (*x)[NumRows][NumColumns])
{
print_mat((int)NumRows, (int)NumColumns, (const float *)x);
}
Now you can use the function naturally:
float matrix[4][3] = { ... };
print_mat( matrix );
This only works, however, as long as you do not let the array downgrade to a pointer.
Also, there are limit issues with the cast from size_t to int, but it really shouldn’t be possible to make one big enough that it would matter.
EDIT: There are also potential buffering/alignment issues when casting a multidimensional array to a one-dimensional, flat array. But no common, modern compiler + hardware that I am aware of where this is an issue. Just be sure to know your target platform.
As noted in comments, C++ does not support variable-length arrays (VLAs). C did from the 1999 standard, but that became optional in C11. In combination, those factors are relevant to why gcc (depending on version) accepts your code, but g++ does not.
In C (and C++ if writing in a C style <blech!>), an alternative is to pass a single-dimensional array (with contiguous elements) to a function that accepts a pointer and use an indexing scheme to access elements. For example, assuming row-major ordering;
void print_mat(const int nr, const int nc, const float *x)
{
for (int ir=0; ir<nr; ir++)
{
int row_start = ir * nc;
for (int ic=0; ic<nc; ic++)
{
printf(" %f",x[row_start + ic]);
}
printf("\n");
}
}
In C++, one can use - depending on which (if any) dimensions are known at compile time;
std::array<std::array<float, nc>, nr> (if array dimensions nc and nr are both fixed at compile time);
std::vector<std::vector<float> > (if neither dimension is known
until run time). Bear in mind that individual std::vector<float>s
in a std::vector<std::vector<float> > CAN have different dimensions. Your caller will need to ensure dimensions are the same for all contained std::vector<float>s and/or your function will need to check sizes.
If nc is fixed at compile time but nr is not, you can use std::vector<std::array<float, nc> >. If nr is fixed at compile time, but nc is not, you can use std::array<std::vector<float>, nr>.
If you must pass the entire vector/array, usually better to pass it by reference than by value. For example;
void print_mat(const std::array<std::array<float, nc>, nr> &)
{
// definition
}
or (if you need to pass around some arrays of different dimensions) create a family of such functions
template<int nc, int nr>
void print_mat(const std::array<std::array<float, nc>, nr> &)
{
// definition
}
Personally, I would not actually pass arrays or vectors around. I'd use iterators, such as;
template<class NestedIterator>
void print_mat(NestedIterator row, NestedIterator end_row)
{
while (row != end_row)
{
auto col = std::begin(*row); // Assuming C++11 and later
auto col_end = std::end(*row);
while (col != col_end)
{
std::cout << ' ' << *col;
++col;
}
std::cout << '\n'; // or std::endl
++row;
}
}
This function assumes begin and end iterators from a container that contains (nested) containers (so passing iterators from a std::vector<float> will be a diagnosable error). It works for any type of element (e.g. is not limited to float in your case), that can be streamed to a std::ostream.
I've assumed row-major ordering in the above. The adjustments for column-major ordering are trivial.
How am I supposed to pass static 2d array to function in cpp as an argument? I tried something like that:
void foo(int (&tab)[N][N]) {
// function body
}
int main() {
int n;
cin >> n;
int tab[n][n];
foo(tab); // doesn't work
return 0;
}
I get "no matching function error" when I try to call foo.
I need static arrays, because vectors are too slow for my needs. I would like to avoid declaring array with 10000 rows and columns, too. Moreover, I would want to use functions, because it will make my code readable. Is there any solution for this problem which will meet my expectations?
With cin >> n;int tab[n][n];, you declare a variable length array (i.e. an array which's dimensions are not compile-time-constants).
You have two problems here: First, they are not supported by standard C++, and second they are not compatible with fixed size array parameters you introduced.
If you declare your array with compile time known size, however, it will work:
#define N 10
void foo(int (&tab)[N][N]) {
cout << tab[1][1] << endl;
}
int main() {
int tab[N][N] = {};
tab[1][1]=15;
foo(tab);
return 0;
}
The classical C++ solution would involve using vectors of vectors. If it's not suitable (because you want more speed or more control over memory), you can define your own class for a square 2-D array.
One idea I used in my code is, implement it using an underlying 1-D vector, with accessor method returning a pointer.
struct My_2D_Array
{
explicit My_2D_Array(size_t n):
m_size(n),
m_data(n * n)
{
}
int* operator[](size_t i)
{
return m_data.data() + i * m_size;
}
size_t m_size;
std::vector<int> m_data;
};
This not only lacks all sanity checks, and also makes bound-checked access impossible (because the accessor returns a bare pointer), but will work as a quick-and-dirty solution.
Usage in your code:
int foo(My_2D_Array& matrix)
{
// example
return matrix[2][3] + matrix[3][2];
}
int main()
{
int n;
cin >> n;
My_2D_Array tab(n);
foo(tab);
return 0;
}
This idea is highly customizable - you can make the code for My_2D_Array as simple or as clever as you want. For example, if you still don't like usage of vector, even though it's 1-D, you can manage (allocate/deallocate) your memory separately, and store int*, instead of vector<int>, in My_2D_Array.
Just use a vector<> of vector<int>. No need for mucking around with non-standard arrays.
What is the equivalent matrix-like C-array of a nested std::vector (for C and C++ interop)?
For example, if one wanted to treat std::vector<std::vector<int>> as some kind of int arr[n][m], where n is the dimension of the outer vector and m of the inner vector, then what structure would one use in C?
This is motivated by wanting to have a similar correspondence between matrices in C and C++ as for vectors in:
https://stackoverflow.com/a/1733150/4959635
Based on additional information in the comments, let me suggest you do something like this instead:
class TwoDimVector {
public:
TwoDimVector(int num_cols, int num_rows)
: m_num_cols(num_cols)
, m_num_rows(num_rows)
, m_data(m_num_cols * m_num_rows, 0)
{ }
int & ix(int row, int col) {
return data[num_cols * row + col];
}
const int m_num_rows;
const int m_num_cols;
private:
std::vector<int> m_data;
}
When you do nested vectors, there's a lot of extra work happening. Also, with nested vectors, the data is not contiguous, making it hard to work with any C-apis. Notice with this data structure, the size is fixed at construction time and accessible. This is designed to be row contiguous, so for C interoperability you can access extra raw pointers like so:
TwoDimVector tdv(4,3);
int * raw = &tdv.ix(0,0);
int * raw_second_row = &tdv.ix(1,0);
Just note: if you pass this into a function, be sure to pass by reference:
void do_work(TwoDimVector & tdv) {
...
}
If you don't pass by reference, it will copy everything, which is a bunch of (typically unnecessary) work.
Maybe, this code
void translate(const vector< vector >& vec){
int m = vec.size(), n = 0;
for (vector<int>& deep : vec) // search maximum size if nested vectors
{
if (deep.size() > n)
n = deep.size();
}
int arr[m][n];
m = n = 0;
for (vector<int>& deep : vec){
for (int& x : deep)
{
arr[m][n] = x;
++n;
}
++m;
}
// So, I really don't know how you can return this array :(
}
You see, it code is BAD, you mustn't do it !!!
If you writing on C++ you should using std::vector - it is easier.
C-like arrays is heritage from C, you shouldn't using they
I have 2 2D arrays that represent a maze
const char maze1[10][11]
and
const char maze2[20][21]
I'm trying to create 1 function to handle both mazes like so:
void solveMaze(maze[][])
{
}
and just pass the maze like solveMaze(maze1);
How would I do this with function templates?
I recently asked this question already but explicitly asked not to use function templates because I wasn't sure on how to use it, but I would like to see how it would work. (hope this isn't "abusing" the system)
You do not need and should not use templates to solve this problem. All you are doing is solving mazes of different sizes.
Templates are for the generation of a number of classes/functions that use various types.
Instead construct a class to store a maze. This class should store the dimentsions of the maze and give access to the components of that maze.
First of all, it would be much simpler if you were using better arrays. The issue with C-arrays is that they have a tendency to decay to pointers easily, and once they do, the size is lost (and that, my dear, is pretty stupid as far as I am concerned...)
The choice then depends on whether you have fixed-size arrays or want dynamically-sized arrays:
for fixed-size: std::array (or if unavailable boost::array)
for dynamically-size: std::vector
Since a template will make more sense in the std::array case, I'll suppose that is what you elected.
char const maze1[10][11]
is equivalent to
std::array<std::array<char, 11>, 10> const maze1
It's slightly more verbose, but std::array proposes regular member methods like .size(), .begin(), .end(), etc... and it can be passed in functions easily.
Now, on to your template functions. The signature will simply be:
template <size_t M, size_t N>
void solveMaze(std::array<std::array<char, N>, M> const& maze);
However, despite your question, you more likely want not to use templates here (they are of little benefits). So I would advise using vector and a regular functions:
void solveMaze(std::vector< std::vector<char> > const& maze);
template<int w, int h>
void solveMaze(const char (&maze)[w][h])
{
//can use w,h now
}
There is no real support for multidimensional Arrays. You should consider using a class with proper support for the dimensions. The following does the trick
template<int N, int M>
void solveMaze(const char (&maze)[N][M]) {
size_t n = N;
size_t m = M;
int x = 0;
}
int main(int argc, char *argv[])
{
const char maze[3][2] = { { 0, 1} , {2, 3}, {4, 5} };
solveMaze(maze);
return 0;
}
I have got a small problem with 1D array in c++. I have got a function line this:
void func(int (&array)[???])
{
// some math here;
"for" loop {
array[i] = something;
}
}
I call the functions somewhere in the code, and before I made math I'm not able to know dimension of the array. The array goes to the function as a reference!, because I need it in the main() function. How I can allocate array like this?, so array with ?? dimension goes to the function as reference then I have to put the dimension and write to it some values.
Since you're using C++, why not use a std::vector<> instead?
Other have mentioned that you should use std::vector in C++ and they are right.
But you can make your code work by making func a function template.
template <typename T, size_t N>
void func(T (&array)[N])
{
// some math here;
"for" loop {
array[i] = something;
}
}
Use a pointer, not a reference:
void func(int *a, int N);
Or, easier, use a vector:
void func(std::vector<int> &a);
Vectors can be allocated by simply saying
std::vector<int> a(10);
The number of elements can be retrieved using a.size().
If the array you pass to func is a stack array, and not a pointer, you can retain its size by using a function template:
template <class T, size_t N>
void func(T(&array)[N])
{
size_t array_length = N; // or just use N directly
}
int main()
{
int array[4];
func(array);
}
That said, as others have already pointed out, std::vector is probably the best solution here.
As well as vector which has been suggested you could possibly use valarray which is also part of STL and is intended specificially to handle mathematical collections.
What you have to realize, is that arrays are pointers. A definition like int array[5] will allocate space for 5 integers on the stack and array will be the address of the first value. Thus, to access the first value in the array, you can write
array[0] or *array (which is the same as *(array + 0))
In the same way to retrieve the address of the third element, you can write
&array[2] or array + 2
Since arrays are pointers, you don't have to worry about the runtime size of your array if you would like to pass it to a function, simply pass it as a pointer:
void func(int *array)
{
int size;
//compute size of the array
for (int i = 0; i < size; ++i)
{
//do whatever you want with array[i]
}
}