3

When I want to initiate a multidimensional array, I usually just use pointers. For example, for two dimensions I use:

double **array

and for three I use:

double ***array

However, I'd like to set a multidimensional array based on a command line argument indicating the dimension. Is there are way to set an array of arbitrary size once you have a variable with the number of dimensions you'd like?

18
  • 4
    Have you looked into using a third-party library? To me, it sounds like you're looking for a matrix class; Eigen is a good option. Commented Oct 31, 2013 at 14:44
  • 1
    You can try use void* Commented Oct 31, 2013 at 14:46
  • 1
    Unless you specifically need arbitrary row-length-allocation size within the matrix, there is absolutely no reason whatsoever to do this in a modern C++ program (and even that isn't a valid reason with a decent amount of engineering forethought). Commented Oct 31, 2013 at 14:52
  • 3
    When I want to initiate a multidimensional array, I usually just use pointers. <-- That is a sign you are doing something wrong ... Commented Oct 31, 2013 at 14:54
  • 2
    @MichaelLeVine The most basic method is a vector of vectors. The rest of your question (dealing with an arbitrary number of dimensions) is a design issue: array dimensions mean something in the context of an application. An arbitrary number of dimensions indicates you are trying to change the meaning to an instance of the application. It is possible, but very messy, and as a practical application is an indication that you did not properly think about your design. Commented Oct 31, 2013 at 15:01

2 Answers 2

1

Even though this whole question is an indication of a design flaw, you can (sort of) accomplish this:

template<typename T>
class MultiArray
{
public:
    MultiArray(std::size_t dimen, std::size_t dimen_size) : _dimensions(dimen)
    {
        _data = new T[dimen * dimen_size];
    }

    // implment copy constructor, copy-assignment operator, destructor, and move constructors as well

    T* operator[](int i)
    {
        assert(0 <= i && i < _dimensions); // bounds check for your dimension
        return &_data[i];
    }
private:
    T* _data;
    std::size_t _dimensions;
};

int main()
{
    MultiArray<int> a(5, 2);
    a[4][1] = 3;
    std::cout << a[4][1] << std::endl;
    return 0;
}

If you want it jagged, you would have to do more math and maintenance regarding the bounds for each "dimension".

The problem you run into has making the dimensions mean something for your application. Typically, a multi-dimensional array represents something (e.g. a 2D vector can represent Cartesian space, a 3D or 4D vector can be used for manipulating data for 3D graphics). Beyond the 4th dimension, finding a valid meaning for the array becomes murky and maintaining the logic behind it becomes increasingly complex with each new dimension.

Sign up to request clarification or add additional context in comments.

3 Comments

What would you suggest as a smart way to design a structure to solve this problem: I have n terms in a function, each with m possible forms. I need to calculate all values for any combination of the n terms with all the possible m forms of the terms.
@MichaelLeVine What you just described is a 2 dimensional array (one dimension for your forms, the other for the elements on each form). It is basically a permutations calculation.
No, but I also need to store the function output of arbitrary combinations of the terms with arbitrary forms of the terms. I'm solving a combinatorial problems that requires a recursive algorithm, so I need to be able to look up previous outputs (because looking them up is several times faster than recalculating).
1

you may be interested in the following code which allow you to use any "dynamic" dimension:

#include <cassert>
#include <cstddef>

#include <vector>

template<typename T>
class MultiArray
{
public:
    explicit MultiArray(const std::vector<size_t>& dimensions) :
        dimensions(dimensions),
        values(computeTotalSize(dimensions))
    {
        assert(!dimensions.empty());
        assert(!values.empty());
    }

    const T& get(const std::vector<size_t>& indexes) const
    {
        return values[computeIndex(indexes)];
    }
    T& get(const std::vector<size_t>& indexes)
    {
        return values[computeIndex(indexes)];
    }

    size_t computeIndex(const std::vector<size_t>& indexes) const
    {
        assert(indexes.size() == dimensions.size());

        size_t index = 0;
        size_t mul = 1;

        for (size_t i = 0; i != dimensions.size(); ++i) {
            assert(indexes[i] < dimensions[i]);
            index += indexes[i] * mul;
            mul *= dimensions[i];
        }
        assert(index < values.size());
        return index;
    }

    std::vector<size_t> computeIndexes(size_t index) const
    {
        assert(index < values.size());

        std::vector<size_t> res(dimensions.size());

        size_t mul = values.size();
        for (size_t i = dimensions.size(); i != 0; --i) {
            mul /= dimensions[i - 1];
            res[i - 1] = index / mul;
            assert(res[i - 1] < dimensions[i - 1]);
            index -= res[i - 1] * mul;
        }
        return res;
    }

private:
    size_t computeTotalSize(const std::vector<size_t>& dimensions) const
    {
        size_t totalSize = 1;

        for (auto i : dimensions) {
            totalSize *= i;
        }
        return totalSize;
    }

private:
    std::vector<size_t> dimensions;
    std::vector<T> values;
};

int main()
{
    MultiArray<int> m({3, 2, 4});

    m.get({0, 0, 3}) = 42;
    m.get({2, 1, 3}) = 42;

    for (size_t i = 0; i != 24; ++i) {
        assert(m.computeIndex(m.computeIndexes(i)) == i);
    }
    return 0;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.