3D array to 2D ptr casting...

J

John Ratliff

Say I had a three-dimensional array containing multiple 2D level data.

It might be defined like this:

unsigned char LEVEL_DATA[][5][5] = {
{
{1, 1, 1, 1, 1},
{1, 0, 0, 0, 1},
{1, 0, 0, 0, 1},
{1, 0, 0, 0, 1},
{1, 1, 1, 1, 1}
}
};

Assume of course there are more dimensions and more than one level.

What is the proper way to cast to a 2D const ptr? This is what I did to
make the compiler shut up, but I don't know if it's correct or not.

const unsigned char * const *data =
reinterpret_cast<const unsigned char * const *>(LEVEL_DATA[0]);

Is this correct? I was reading
http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.17
But it doesn't mention pre-defined array data specifically, and the
compiler doesn't implicitly treat them the same (yeah, I know they are
not the same).

Thanks,

--John Ratliff
 
J

John Ratliff

John said:
Say I had a three-dimensional array containing multiple 2D level data.

It might be defined like this:

unsigned char LEVEL_DATA[][5][5] = {
{
{1, 1, 1, 1, 1},
{1, 0, 0, 0, 1},
{1, 0, 0, 0, 1},
{1, 0, 0, 0, 1},
{1, 1, 1, 1, 1}
}
};

Assume of course there are more dimensions and more than one level.

What is the proper way to cast to a 2D const ptr? This is what I did to
make the compiler shut up, but I don't know if it's correct or not.

const unsigned char * const *data =
reinterpret_cast<const unsigned char * const *>(LEVEL_DATA[0]);

Is this correct? I was reading
http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.17
But it doesn't mention pre-defined array data specifically, and the
compiler doesn't implicitly treat them the same (yeah, I know they are
not the same).

Well, the reinterpret_cast is clearly wrong.

I'm still not sure how to make a pointer to array data, but I changed my
code to avoid making one.

--John Ratliff
 
F

Frank Chang

John Ratliff, I tried your example with and without const pointers and
found that although it compiled , it exhibited non-defined behavior at
run-time.
I checked in Margaret Ellis and Bjarne Strousup's ARM and they state :
"An array is one-dimensional : talking about multidimensional arrays in
C/C++ is simply referring to a conventional use of arrays of arrays."
With that advice in mind, I think an alternative might be to write a
C++ class implementing the three-dimensional array abstraction. Then,
in the class, you could write an member operator which converts a
three-dimensional array to a 2 dimensional const ptr.
Also, there is a boost library multi_array class which you can
either in a composition pattern or a single inheritance pattern. Thank
you.




John said:
John said:
Say I had a three-dimensional array containing multiple 2D level data.

It might be defined like this:

unsigned char LEVEL_DATA[][5][5] = {
{
{1, 1, 1, 1, 1},
{1, 0, 0, 0, 1},
{1, 0, 0, 0, 1},
{1, 0, 0, 0, 1},
{1, 1, 1, 1, 1}
}
};

Assume of course there are more dimensions and more than one level.

What is the proper way to cast to a 2D const ptr? This is what I did to
make the compiler shut up, but I don't know if it's correct or not.
Is this correct? I was reading
http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.17
But it doesn't mention pre-defined array data specifically, and the
compiler doesn't implicitly treat them the same (yeah, I know they are
not the same).

Well, the reinterpret_cast is clearly wrong.

I'm still not sure how to make a pointer to array data, but I changed my
code to avoid making one.

--John Ratliff
 
J

John Ratliff

Frank said:
John Ratliff, I tried your example with and without const pointers and
found that although it compiled , it exhibited non-defined behavior at
run-time.
I checked in Margaret Ellis and Bjarne Strousup's ARM and they state :
"An array is one-dimensional : talking about multidimensional arrays in
C/C++ is simply referring to a conventional use of arrays of arrays."
With that advice in mind, I think an alternative might be to write a
C++ class implementing the three-dimensional array abstraction. Then,
in the class, you could write an member operator which converts a
three-dimensional array to a 2 dimensional const ptr.

I thought about this, but that seemed like a lot of work.

Unless you had a different idea, I would either have to a) cast to a 1D
array and doing ptr math, or b) build a new 2D array using pointers from
the 3D array.

Since I got around using a new variable for the 2D array, I suppose it
doesn't matter.

And yeah, I got the same undefined behaviour. reinterpret_cast allowed
the cast, but didn't know what to do once it had done it.
Also, there is a boost library multi_array class which you can
either in a composition pattern or a single inheritance pattern. Thank
you.

I've heard a lot about boost. But since I got around converting my array
at all, I think I'll just leave it as is.

If I were reading the level data from file instead of having them
already pre-defined in the code, I could do something like this:

-------------
#include <iostream>

unsigned char LEVEL_DATA[][5][5] = {
{
{1, 1, 1, 1, 1},
{1, 0, 0, 0, 1},
{1, 0, 0, 0, 1},
{1, 0, 0, 0, 1},
{1, 1, 1, 1, 1}
}
};


class LevelData {
private:
unsigned char ***LEVEL_DATA;

public:
LevelData();
~LevelData();
const unsigned char * const *getData(int level) const;
};

inline const unsigned char * const *LevelData::getData(int level) const {
return
static_cast<const unsigned char * const *>(LEVEL_DATA[level]);
}

LevelData::LevelData() {
LEVEL_DATA = new unsigned char **;
LEVEL_DATA[0] = new unsigned char *[5];

for (int i = 0; i < 5; i++) {
LEVEL_DATA[0] = new unsigned char[5];
}

for (int y = 0; y < 5; y++) {
for (int x = 0; x < 5; x++) {
LEVEL_DATA[0][y][x] = ::LEVEL_DATA[0][y][x];
}
}
}

LevelData::~LevelData() {
for (int i = 0; i < 5; i++) {
delete [] LEVEL_DATA[0];
}

delete [] LEVEL_DATA[0];
delete LEVEL_DATA;
}

int main(int, char **) {
LevelData levels;
const unsigned char * const *data = levels.getData(0);

for (int y = 0; y < 5; y++) {
for (int x = 0; x < 5; x++) {
std::cout << static_cast<int>(data[y][x]) << ' ';
}

std::cout << '\n';
}

return 0;
}
 
F

Frank Chang

John, I believe your solution is an elegant one. I haven't tested it
yet. Yesterday, I wrote to you:

" I think an alternative might be to write a
C++ class implementing the three-dimensional array abstraction. Then,
in the class, you could write an member operator which converts a
three-dimensional array to a 2 dimensional const ptr."

I think your class differs from my proposed class principally in the
respect that you use the getData(int) member function instead of an
member operator()[int] to cast a 3D array to an const 2D pointer. I
think the stumbling block was that you and I were trying to directly
convert from unsigned char LEVEL_DATA[][5][5] = {
{
{1, 1, 1, 1, 1},
{1, 0, 0, 0, 1},
{1, 0, 0, 0, 1},
{1, 0, 0, 0, 1},
{1, 1, 1, 1, 1}
}
};
to a const 2D pointer. I like how you circumvented that problem by
using a member variable, unsigned char ***LEVEL_DATA, in your
LevelData class. I will have to remember your solution in case I ever
need to do something similar in the future. Thank you for the reply.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top