multidimensional-array 3d - Is it bad practice to use multi-dimensional arrays in C/C++?




pointer dynamic (9)

Do you need to store multi-dimensional data where you know the dimensions ahead of time? If so, use a multi-dimensional array.

If you don't know the dimensions ahead of time (i.e., you're going to have to dynamically allocate the array), then you either need to either

  • allocate a one-dimensional array and emulate an n-dimensional array using index arithmetic, or
  • allocate an array of pointers to arrays of elements to get actual multidimensional array semantics

It depends on the specific use case, but as a rule of thumb, I almost always prefer the former because it makes for less memory management hassle and fewer heap allocations. The complexity for both approaches grows as the number of dimensions increases, but, in my opinion, it grows much faster for the latter approach due to the extra levels of indirection.

Some programmers seem to violently hate them, while others seem to think they're fine. I know that anything that can be done to a multi-dimensional array can also be done to a regular array, so they're functionally equivalent. Is it bad practice to use multi-dimensional arrays, or does it not matter?


It may be possible to store multi-dimensional data in a single-data array, but you have to keep track of the indexes yourself. Multi-dimensional arrays are actually stored in memory as a single dimensional array, with syntax to support representing that data as multi-dimensional.

If you are working with multi-dimensional data, then I feel it is most appropriate to choose the correct tool for the job (a multi-dimensional array).




Well, in C++ I dislike multidimensional arrays because they should be replaced with std::vector<std::vector<t> >. They're also particularly important if you want to represent a std::vector<std::basic_string<t> >.

Multidimensional arrays are so simple a primitive I'm suprised most would care. However, a design that uses a single dimension is probably better than one using multiple dimensions, all other things being equal.


Advantages of multi-dim arrays to Vector<Vector<>>

  1. Easy to type [ ][ ]
  2. C compatible.
  3. Simple to understand conceptually what is it is doing.

Disadvantages:

  1. No easily detected bounds checking. Bounding off the end of the outer brackets usually overflows into memory allocated by the inner brackets making these types of error a real pain to track.
  2. Jagged arrays require care to set up. Vector pattern is easy.
  3. Multidimensioal arrays are more than double pointers making it a pain to pass into functions correctly. Most of the time, I've seen them just passed as a raw address to a double pointer which defeats the intrinsic math the compiler will do for you.

Basically though, it comes down to lack of bounds checking for me.


There are following advantages of multi-dimensional arrays over Vector<Vector<>>:

  • They are easy to understand.
  • Searching and sorting of elements can be done very easily.
  • They are compatible with C.
  • They are easy to type.

I know that anything that can be done to a multi-dimensional array can also be done to a regular array

I do not think that's entirely accurate. We'll need an array of pointers to store something as basic as a list of names and then sorting it. Or pointers to pointers to store a variable length string and then a list of such strings. As the original questions mentions only arrays per se, can't see how problems like these can be done with equal ease in a regular array. Please consider not just storing the strings in a 1-D array (using some sort of separator maybe) but also performing operations such as sorting.


A concrete example to clarify the concern. Imagine you have a situation where you have 2 libraries, foo and bar, each with their own namespace:

namespace foo {
    void a(float) { /* does something */ }
}

namespace bar {
    ...
}

Now let's say you use foo and bar together in your own program as follows:

using namespace foo;
using namespace bar;

void main() {
    a(42);
}

At this point everything is fine. When you run your program it 'does something'. But later you update bar and let's say it has changed to be like:

namespace bar {
    void a(float) { /* does something completely different */ }
}

At this point you'll get a compiler error:

using namespace foo;
using namespace bar;

void main() {
    a(42);  // error: call to 'a' is ambiguous, should be foo::a(42)
}

So you'll need to do some maintenance to clarify which 'a' you meant (i.e. foo::a). That's probably undesirable, but fortunately it is pretty easy (just add foo:: in front of all calls to a that the compiler marks as ambiguous).

But imagine an alternative scenario where bar changed instead to look like this instead:

namespace bar {
    void a(int) { /* does something completely different */ }
}

At this point your call to a(42) suddenly binds to bar::a instead of foo::a and instead of doing 'something' it does 'something completely different'. No compiler warning or anything. Your program just silently starts doing something complete different than before.

When you use a namespace you're risking a scenario like this, which is why people are uncomfortable using namespaces. The more things in a namespace the greater the risk of conflict, so people might be even more uncomfortable using namespace std (due to the number of things in that namespace) than other namespaces.

Ultimately this is a trade-off between writability vs reliability/maintainability. Readability may factor in also, but I could see arguments for that going either way. Normally I would say reliability and maintainability are more important, but in this case you'll constantly pay the writability cost for an fairly rare reliability/maintainability impact. The 'best' trade-off will determine on your project and your priorities.







c++ c multidimensional-array