Int [n] [m] where n and m are known at runtime

I often need to create a 2D array with width and height (let them be n and m) unknown at compile time, usually I write:

vector<int> arr(n * m);

      

And I access the elements manually with:

arr[j * m + i] 

      

I was recently told that I could write:

int arr[n][m] // n and m still only known at runtime.

      

So here are 2 questions:

  • Is this behavior allowed by the C ++ standard?
  • How to pass such an array to a function? g ++ says that arr is of type int (*)[n]

    , but again n is dynamic and unknown outside of the function where it is declared ( main

    ).
+3


source to share


2 answers


The function you are asking about (where dimensions are only known at runtime) is a non-standard C ++ extension but standard in C.99 (done in an optional function in C.11). This function is called Variable Length Array (VLA) and the link is the documentation for GCC.

If you are using GCC, you must pass the length of the array as a parameter to the function.

void foo (int m, int arr[][m]) {
    //...
}

      

However , there seems to be an error in the compiler or documentation, as the above function prototype syntax only works when compiling C code, not C ++ (in gcc version 4.8.2), the only thing I found was to use a parameter void *

and overlay it on the function body:

int foo_workaround (int m, void *x)
{
    int (*arr)[m] = static_cast<int (*)[m]>(x);
    //...
}

      

There are other solutions if you don't want to rely on a compiler extension. If you don't mind a separate distribution for each row, you can use a vector of vectors, for example:



std::vector<std::vector<int> > arr(n, std::vector<int>(m));

      

However, if you need a separate selection box, as you demonstrated in your own example, then it is better to create a wrapper class around vector

to give you a syntax like 2-d.

template <typename T>
class vector2d {

    int n_;
    int m_;
    std::vector<T> vec_;

    template <typename I>
    class vector2d_ref {
        typedef std::iterator_traits<I> TRAITS;
        typedef typename TRAITS::value_type R_TYPE;
        template <typename> friend class vector2d;
        I p_;
        vector2d_ref (I p) : p_(p) {}
    public:
        R_TYPE & operator [] (int j) { return *(p_+j); }
    };

    typedef std::vector<T> VEC;
    typedef vector2d_ref<typename VEC::iterator> REF;
    typedef vector2d_ref<typename VEC::const_iterator> CREF;

    template <typename I> 
    vector2d_ref<I> ref (I p, int i) { return p + (i * m_); }

public:

    vector2d (int n, int m) : n_(n), m_(m), vec_(n*m) {}
    REF operator [] (int i) { return ref(vec_.begin(), i); }
    CREF operator [] (int i) const { return ref(vec_.begin(), i); }

};

      

The wrapper operator[]

returns an intermediate object, which it also overloads operator[]

to allow two-dimensional array syntax when using the wrapper.

    vector2d<int> v(n, m);
    v[i][j] = 7;
    std::cout << v[i][j] << '\n';

      

+5


source


Why not have std::vector

out std::vector

?

std::vector<std::vector<int> > arr(n, std::vector<int>(m));

      



Element access becomes as follows:

std::cout << "(2,1) = " << arr[2][1] << std::endl;

      

+2


source







All Articles