1

I've just started to learn C++.

I have to declare a method that will accept variables like this ones:

int grid1[200][200];
int grid2[20][25];
int grid3[53][40];

How do I have to declare that parameter in the method?

I have found this declaration, but I don't know if it is useful or how can I use it:

int** a = new int*[rowCount];

I will copy that parameter to a member variable that will be dynamic (I think it will be in the heap, so this is why it is dynamic).

VansFannel
  • 41,682
  • 96
  • 329
  • 561
  • With complexity. Why do you need to pass around 2D C arrays? You're better off not... – Lightness Races in Orbit Aug 04 '19 at 13:46
  • Don't use a raw C-style array. What you want is a `std::vector`. – Jesper Juhl Aug 04 '19 at 13:49
  • Don't use raw c-style arrays in c++ code please! – πάντα ῥεῖ Aug 04 '19 at 13:49
  • @πάνταῥεῖ I've just started to learn. What do you suggest me? – VansFannel Aug 04 '19 at 13:49
  • Which book are you using? – Lightness Races in Orbit Aug 04 '19 at 13:51
  • @JeJo Please don't teach that outdated and inaccurate terminology – Lightness Races in Orbit Aug 04 '19 at 13:52
  • @LightnessRacesinOrbit None. – VansFannel Aug 04 '19 at 13:52
  • So, instead of using old 2D C arrays, are you suggesting me to use std::vector?? – VansFannel Aug 04 '19 at 13:53
  • https://stackoverflow.com/q/388242/5910058 – Jesper Juhl Aug 04 '19 at 13:54
  • 3
    @VansFannel Found the problem! Stack Overflow doesn't scale well for teaching the basics of the language, or it's all we'd ever do. Start [here](https://stackoverflow.com/q/388242/560648). Have fun! – Lightness Races in Orbit Aug 04 '19 at 13:55
  • @LightnessRacesinOrbit My intention was to specify the difference to OP, didn't care about the C++ standard terminologies, therefore. Sorry for the misleadings, if any. BTW, I am not the only one in SO who still want to refer those terminologies in C++ tags. – JeJo Aug 04 '19 at 13:56
  • 1
    @JeJo I know, that's why I'm trying to stamp it out :P – Lightness Races in Orbit Aug 04 '19 at 13:57
  • @VansFannel "So, instead of using old 2D C arrays, are you suggesting me to use std::vector?" - Yes. For statically sized arrays, use [std::array](https://en.cppreference.com/w/cpp/container/array). For dynamically sized arrays use [std::vector](https://en.cppreference.com/w/cpp/container/vector). Don't ever use raw C arrays unless some weird situation forces it on you. And get a [good book](https://stackoverflow.com/q/388242/5910058) or two to read. – Jesper Juhl Aug 04 '19 at 13:57
  • @JesperJuhl you can add an answer with your comment and I will accept it. I will look for an example about how to get an element from a std::vector using row and column (like it was an old 2D C array). – VansFannel Aug 04 '19 at 14:03
  • 1
    `int** a = new int*[rowCount];` is a relic of the 1990s – M.M Aug 04 '19 at 14:44
  • @VansFannel *I have to declare a method that will accept variables like this ones:* -- To sum up everything, your `int**` would never work, since a 2 dimensional array is *not* an `int**`. An `int**` is a pointer to an `int*` -- these are not arrays. So either you start from scratch with everything being an `int**`, (i.e. `int** grid1; int **grid2;...`) and work from there, or scrap that and use the techniques described in the answers. – PaulMcKenzie Aug 04 '19 at 15:36
  • Also, if you were to say "I'm bold and want to use `int**`", see [this answer](https://stackoverflow.com/questions/21943621/how-to-create-a-contiguous-2d-array-in-c/21944048#21944048) to keep better cache locality and not have your array rows all over the heap. – PaulMcKenzie Aug 04 '19 at 15:39
  • [related](https://stackoverflow.com/questions/8767166/passing-a-2d-array-to-a-c-function) –  Aug 04 '19 at 22:17

2 Answers2

4

For statically sized arrays, use std::array. For dynamically sized arrays use std::vector. Don't ever use raw C arrays unless some weird situation forces it on you.

If you need a multi dimensional array, you can of course use std::vector<std::vector<int>> or similar for std::array. This is easy and convenient since you can do myarray[row][column] (and possibly good enough). But a better performing option is usually to just declare a 1D std::vector<int> with a size of "dimension 1 * dimension 2" and then, when indexing into it, do myvector[row_number * size_of_row + column]. Treating a 1D array as a 2D one is as easy as that and it is likely to perform better since it's friendlier to your CPUs prefetcher and cache hierarchy.

As for declaring a function to accept such arrays - it's straight forward. For example:

void f(const std::array<int, 666>& myarray);
void f(const std::array<std::array<int, 42>, 666>& myarray);
void f(const std::vector<int>& myarray);
void f(const std::vector<std::vector<int>>& myarray);
Jesper Juhl
  • 1
  • 3
  • 38
  • 63
2

Use std::vector and forget everything related to plain arrays.

void foo(vector<vector<int>>& v)
{
    ...
}


// now you have a 100x50 double array
vector<vector<int>> x;
x.resize(100);
for(auto& xx : x)
{
    xx.resize(50);
}
foo(v);

If you care about caching as the comment mentions, you can create a single dimensional vector and convert it to a multidimensional array, I had previous asked about that here for dynamic arrays. Or if your size is static you can simply:

vector<int> x(100);
int(*yy)[3] = (int(*)[3])x.data(); // Creates a 2D array inside x
yy[0][1] = 5;
yy[1][2] = 4;
yy[2][2] = 10;

Doing internal calculations with rows and columns like x*col + row to manually convert a single dimension array to 2D is bad and error prone.

Michael Chourdakis
  • 8,819
  • 2
  • 32
  • 61
  • 1
    Don't use vectors of vectors. They're poison for your cache. Also, this doesn't answer the question. – Lightness Races in Orbit Aug 04 '19 at 13:47
  • @LightnessRacesinOrbit, so what would be the way to have multidimensional arrays? – Michael Chourdakis Aug 04 '19 at 13:47
  • @LightnessRacesinOrbit I did not ask for the cause, I asked for a solution. – Michael Chourdakis Aug 04 '19 at 13:49
  • If you look at that page for more than a whole thirty seconds you'll see solutions described. Also Related posts on the right-hand side. – Lightness Races in Orbit Aug 04 '19 at 13:49
  • 3
    @MichaelChourdakis You can easily have a 1D array and *treat* it as having 2D. – Jesper Juhl Aug 04 '19 at 13:50
  • 1
    @LightnessRacesinOrbit 1. Make it. 2 Make it work. 3. Make it work fast. In that order. For someone who is starting to learn, a jump straight to 3 is counterproductive. – n. 'pronouns' m. Aug 04 '19 at 14:05
  • @n.m. That's a good general rule but it's over-cited. There is no excuse for using the wrong tool for the job from the outset, particularly when you're teaching. At the _very_ least, you should mention that the solution is suboptimal and ought to be improved in production (as Michael has now done) – Lightness Races in Orbit Aug 04 '19 at 14:12
  • More importantly, though, this still doesn't answer the question. – Lightness Races in Orbit Aug 04 '19 at 14:13
  • "Doing internal calculations with rows and columns like x*col + row to manually convert a single dimension array to 2D is bad and error prone." I don't agree that it's bad. It's pretty straight forward and if you are ever reading an image out of your graphics cards frame buffer, you are going to have to do something like that anyway. But your calculation looks wrong, it should be `x*row+col`, so I guess you win the "error prone" argument after all ;) – Jesper Juhl Aug 04 '19 at 14:40
  • @JesperJuhl yes there are such cases. For someone new in C++, it's unlikely that will be anytime soon with image processing though. – Michael Chourdakis Aug 04 '19 at 14:47