1

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?

hnwoh
  • 128
  • 1
  • 10
  • 1
    This shoudn't even work for a "1D array". C++ doesn't support variable length arrays. – juanchopanza Nov 22 '18 at 20:39
  • What error are getting? This code here shouldn't work because n isn't known until the user inputs a value, where C++ arrays have to be declared and set at compile time. If you want your array to be of variable length you'll likely have to use a vector instead (minor expansion on juanchopanza's comment) – tomh1012 Nov 22 '18 at 20:43
  • @juanchopanza I've seen many people using variable length arrays though... How was that possible? – hnwoh Nov 22 '18 at 20:44
  • I'd use something like this: https://stackoverflow.com/a/2076668/4944425 , but your mileage may vary. – Bob__ Nov 22 '18 at 20:45
  • `tab` isn't a static array and you can't pass 2D auto arrays to functions even with an additional size argument as the last dimension needs to be fixed. – doug Nov 22 '18 at 20:45
  • 1
    Why not double pointer `int **tab`? – ventaquil Nov 22 '18 at 20:47
  • IFAIK you could use VLAs when compiling with gcc because [it has an extension](http://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html) that allows that in C90, ISO C99 and C++. But it is not standard and would not work with every compiler. – Toribio Nov 22 '18 at 20:51
  • Look into `std::array` and `std::vector`. – Jesper Juhl Nov 22 '18 at 20:59
  • 2
    *because vectors are too slow for my needs.* – too slow for what? – Swordfish Nov 22 '18 at 21:03
  • 3
    @ventaquil "double pointer" - Why would you want to do that? Keep code *simple* - more stars usually indicate worse code, not better. Modern C++ has containers, smart pointers and more that you can use to avoid having to use low level stuff and keep things sane (and the abstractions usually optimize away). – Jesper Juhl Nov 22 '18 at 21:03
  • @Swordfish I am implementing TSP solving algorithm, it has to work fast... And even greedy algorithm which is started N times (where N is number of cities - each time i begin in another city) is pretty slow (> 10 minutes) on vectors for ~1000 cities' instances. – hnwoh Nov 22 '18 at 21:12
  • @Mentos1105 I still don't get it. Why does your algorithm have to run N times when the wanted solution is a route that visits every vertex in the graph once. Won't that result in a round trip no matter where you start? – Swordfish Nov 23 '18 at 00:19
  • @Swordfish of course it will, but I am trying to get the shortest path possible (all edges have their length). In order to improve result from greedy algorithm i begin it from each vertex and get minimum from N results I got. Starting vertex does make a slight difference. – hnwoh Nov 23 '18 at 01:45
  • @Mentos1105 When you said `std::vector<>` was to slow ... you have certainly tried? Did you perhaps use a `std::vector>`? – Swordfish Nov 23 '18 at 01:48
  • @Swordfish of course I used vector of vectors, I needed 2 dimensional array. – hnwoh Nov 24 '18 at 15:22
  • 1
    @Mentos1105 Duh! Use *one* vector with size `rows * columns` and calculate the indexes like `(row * columns + col)`. If you know you'll stay in the same row for the next n accesses, cache the index and just do the addition. Term to look up: Cache locality. – Swordfish Nov 24 '18 at 15:27
  • @JesperJuhl good to know. I am not C++ dev so I asked about that. – ventaquil Nov 24 '18 at 21:45
  • @Swordfish thanks for good advice, will be useful for next projects, now I will stay with huge static tables and using just parts of them. – hnwoh Nov 26 '18 at 21:15

3 Answers3

4

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;
}
Stephan Lechner
  • 34,891
  • 4
  • 35
  • 58
  • Yeah, but size of my array is based on data from file which is read by my code earlier. So in order to avoid any slow dynamic data-types I need to declare huge 2-dimensional array and just work on part of it? – hnwoh Nov 22 '18 at 20:49
  • Even that's not possible, since `foo` will always work on a compile-time-constant dimension `N`. you cannot pass anything to it other than an array of dimensions `[N][N]`. Dynamic dimensions imply dynamically allocated arrays. – Stephan Lechner Nov 22 '18 at 20:56
  • Yeah, I meant that in function body i will just use needed part of my array. – hnwoh Nov 22 '18 at 21:00
2

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.

anatolyg
  • 26,506
  • 9
  • 60
  • 134
1

Just use a vector<> of vector<int>. No need for mucking around with non-standard arrays.

Nim
  • 33,299
  • 2
  • 62
  • 101
  • I said in post that vectors are too slow for my needs. – hnwoh Nov 22 '18 at 20:56
  • 1
    @Mentos1105 too slow for what? Thats a weird claim. A vector is as fast as you can get a dynamically sized array – 463035818_is_not_an_ai Nov 22 '18 at 20:58
  • 1
    @Mentos1105 Then use a single vector and view it as a 2D thing. – juanchopanza Nov 22 '18 at 20:59
  • Have you measured it? You can't make broad sweeping statements such as this with out having first done some leg work to verify if a vector is indeed slower (which would be mightily surprising..) Write clean code - let the compiler do it's job. – Nim Nov 22 '18 at 21:08
  • We can only guess what OP is doing with this vector of vectors, which makes it slower than a 2-D VLA. A few reasons for loss of performance are memory fragmentation and separate slow RAM used for heap on an embedded system. But it doesn't really matter; a future visitor having this problem may suffer from a different cause, so a general solution is preferable. – anatolyg Nov 22 '18 at 21:11
  • @Nim I didn't want to go into the details why do I have this problem but I am implementing TSP solving algorithm, it has to work fast... And even greedy algorithm which is started N times (where N is number of cities - each time i begin in another city) is pretty slow (> 10 minutes) on vectors for ~1000 cities' instances. When I started same algorithm based on static arrays, on the same machine, it was done in <1 minute. – hnwoh Nov 22 '18 at 21:16
  • 1
    Fully optimized? And when you say static arrays - do you mean statically sized arrays (compile time) or dynamically allocated arrays? And it's the "details" that will determine whether you get a quality answer or something else - keep that in mind for the future... – Nim Nov 22 '18 at 21:18
  • Statically sized arrays. And both of the algorithms were equally optimized. Thanks for advice, I will. I wanted to be as concise as possible, maybe it was a bad idea. – hnwoh Nov 22 '18 at 21:19