tags:

views:

124

answers:

4

Hi. I have to create a 3-Dimensional array, wich gets allocated at object creation. I've done such stuff before with normal arrays.

typedef unsigned char byte;  // =|
byte ***data;
A: 

Well, as a first guess to how you might want to handle this:

for(int i=0; i < length; ++i){
    data = new char**[size];
    for(int j = 0; j < anotherLength; ++j){
        data[i] = new char*[anotherSize];
        ...

get the idea? Personally I'd go with vector's of vectors with the final component being a string.

wheaties
Generally this is a bad way to deal with this type of thing. The memory ends up being non-contiguous and causes performance problems.
Craig W. Wright
Well, I'll be using this as a Map for a game, so I'll probably just read one value at once... (I'd use `typedef unsigned char byte;` but char is also okay for explainations i thought... -edited-)
aPoC
@Craig W. Wright - never said it was good. I, myself, would use `vector`s as I don't like pointers of pointers of pointers of...
wheaties
+3  A: 

If you're using C++, I strongly advise you using std::vector instead of raw arrays.

Something like:

std::vector<std::vector<std::vector<char> > > data(3, std::vector<std::vector<char> >(3, std::vector<char>(3, 0)));

Will create a 3x3x3 array of chars, all initialized to 0.

You can then access the items the same way you would with a char***:

data[0][0][0] = 1;

Depending on your needs you might also use only one std::vector and inline your three-dimensional space into it. This would fasten both computation and copy operations, as the values would then be in a contiguous block of memory.

The way you could inline the values depending on your needs, but here is an example:

For a 3 dimensional array like this:

a----b
|\   |\
| d----c
e-|--f |
 \|   \|
  h----g

You might store values like this in memory:

a, b, c, d, e, f, g, h

This require some maths, but if you encapsulate this, you can even achieve the same level of usability of a vector of vector of vector, with much higher performances.

ereOn
How much does a vector take of additional memory? (I'll be using sizes like 256x256x64)
aPoC
@aPoC: This is unspecified. However, one can assume it is trivial regarding the data itself. However, if you really are that in into performances, you might want to check my answer again: I edited it to add a much more efficient (even if more complex) alternative.
ereOn
@aPoC: it depends on the implementation, but it will typically contain either three pointers (start, end of data, end of storage) or a pointer and two sizes (start, size, capacity). That's likely to be 12 bytes on a 32-bit system, and 24 bytes on a 64-bit system. Some implementations or build configurations might add extra data to help with debugging. So the overhead for a size like that would be some hundreds of kilobytes.
Mike Seymour
73.728(12*256*64) of 4.268.032 bytes only to contain the pointers, nice! @ereOn So I'd just create a class wich does the calculations and hold that one long array, cool.
aPoC
@aPoC: you might want to check your maths; I make that `12 * (1 + 256 + 256*64) = 199,692`.
Mike Seymour
Aww, even worse, sorry. But then the total bytes are also wrong... I calculated 256*256*64... Why do I have to do it that other way? I think accessing values of that long combined array would also be wrong with arr[x*y*z] ?
aPoC
A: 

Triple indirection is generally a bad way of doing this unless you really need arrays of arrays (e.g., if the size of array[0] has to differ from the size of array[1]). For simple multi-dimensional arrays use something like Boost.MultiArray.

Philipp
+2  A: 

The char*** route will leave you with non-contiguous memory, and this is a major performance problem when things get big. If you must use native arrays I would use a char* and do the following:


const int xDim = ??;
const int yDim = ??;
const int zDim = ??;

char* array = new char[xDim*yDim*zDim];

// Then just create a good indexing scheme.
char getElement(char* array, int x, int y, int z)
{
   // ultimately this is not hard to figure out, but I know I will
   // screw it up here and I don't have time to test the code.
   int element = some function of x,y,z,xDim,yDim,zDim;
   return array[element];
}

That is the basicness of it. If you're going to go down this road though, you should really consider wrapping that char* in a class (maybe Array3D) and have getElement as a member function.

Again though, STL might be more appropriate.

In fact I think the only good reason for not using STL would be to ensure a contiguous chunk of memory, which again char*** will not do.

Craig W. Wright
In retrospect, and like the post above says, you can do the exact same thing with vector<char> as you can with char* in this case. So I don't know that there is any good reason to go with char* versus the STL.
Craig W. Wright
I'd say, vector has more stuff like pre-made functions to add an element, but it takes a bit more time/memory to do. Also it'd be pointless to go with a vector when having something with a static size... using char* you have to write stuff by yourself.
aPoC