-
3D array memory allocation dimensions
Hello,
I am using this piece of code for allocating 3D array in memory by my dimensions HEIGHT, WIDTH, DEPTH, which are variables.
p2DArray = new double**[HEIGHT];
for (int i = 0; i < HEIGHT; ++i) {
p2DArray[i] = new double*[WIDTH];
for (int j = 0; j < WIDTH; ++j)
p2DArray[i][j] = new double[DEPTH];
}
My problem is this: When i have for example HEIGHT = 512, WIDTH = 512 and DEPTH = 2 my 3D allocated array has right dimension in HEIGHT and WIDTH but DEPTH dimensions are not 2, but its larger.
For example when I want to read from p2DArray[511][511][845646] it doesnt say me, that I am out of dimensions (with [845646] in DEPTH), but it will give me random number value. When I want to read on position for example p2DArray[518][511][0] it will say me, that I am out of dimension because of HEIGHT size.
Could you please tell me, why this piece of code allocates 3D array right in HEIGHT and WIDTH dimension, but false in DEPTH (it allocates a lot of bigger in DEPT dimension, than I would like)?
THANKS FOR ANY HELP!
-
Re: 3D array memory allocation dimensions
Quote:
Originally Posted by
Kositch
Hello,
I am using this piece of code for allocating 3D array in memory by my dimensions HEIGHT, WIDTH, DEPTH, which are variables.
p2DArray = new double**[HEIGHT];
for (int i = 0; i < HEIGHT; ++i) {
p2DArray[i] = new double*[WIDTH];
for (int j = 0; j < WIDTH; ++j)
p2DArray[i][j] = new double[DEPTH];
}
My problem is this: When i have for example HEIGHT = 512, WIDTH = 512 and DEPTH = 2 my 3D allocated array has right dimension in HEIGHT and WIDTH but DEPTH dimensions are not 2, but its larger.
Show us a complete program that duplicates the error, not just a piece of code. We can't see into your computer, so there is no way we can verify your claims.
There is nothing wrong with that code (except that it is extremely inefficient).
Regards,
Paul McKenzie
-
Re: 3D array memory allocation dimensions
Quote:
Originally Posted by
Paul McKenzie
Show us a complete program that duplicates the error, not just a piece of code. We can't see into your computer, so there is no way we can verify your claims.
There is nothing wrong with that code (except that it is extremely inefficient).
Regards,
Paul McKenzie
OK, thanks for reply, here is the code example with my problem:
short int ***test;
int HEIGHT = 10;
int WIDTH = 20;
int DEPTH = 3;
test = new short int**[HEIGHT]; //allocating memory for arry of size 10 x 20 x 3
for (int x = 0; x < HEIGHT; ++x) {
test[x] = new short int*[WIDTH];
for (int y = 0; y < WIDTH; ++y)
test[x][y] = new short int[DEPTH];
}
for (int z = 0; z < DEPTH; z++) //filling it with ones
{
for (int y = 0; y < WIDTH; y++)
{
for (int x = 0; x < HEIGHT; x++)
{
test[x][y][z] = 1;
}
}
}
cout << test[5][15][2]; //it will write number one, its ok
cout << test[5][15][5]; //it should say, that i am off the array size with number 5 in depth dimension (program should throw exception), but it will write some random number -21598 and doesnt throw any exception, that i am looking out of allocated memory
-
Re: 3D array memory allocation dimensions
Quote:
Originally Posted by
Kositch
cout << test[5][15][5]; //it should say, that i am off the array size with number 5 in depth dimension (program should throw exception),
Where did you get that erroneous information from?
Quote:
but it will write some random number -21598 and doesnt throw any exception, that i am looking out of allocated memory
Welcome to the world of C++ programming.
When you make a mistake such as writing outside the boundaries of an array in a C++ program, there is nothing that guarantees how your program will behave. The program may throw an exception, or it may work without anything happening, or may throw an exception when run on your machine but run without anything happening on another machine, plain old crash without an exception, etc.
C++ is not Java or C#, or some other computer language that has these checks at runtime and automatically will inform you of a problem.
Regards,
Paul McKenzie
-
Re: 3D array memory allocation dimensions
Quote:
Originally Posted by
Paul McKenzie
Where did you get that erroneous information from?Welcome to the world of C++ programming.
When you make a mistake such as writing outside the boundaries of an array in a C++ program, there is nothing that guarantees how your program will behave. The program may throw an exception, or it may work without anything happening, or may throw an exception when run on your machine but run without anything happening on another machine, plain old crash without an exception, etc.
C++ is not Java or C#, or some other computer language that has these checks at runtime and automatically will inform you of a problem.
Regards,
Paul McKenzie
Thanks for explanation, but why i am making memory allocation, when i can read from array also out of its boundaries?
So my code is right and it allocates only memory that i need?
-
Re: 3D array memory allocation dimensions
Quote:
Originally Posted by
Kositch
why i am making memory allocation, when i can read from array also out of its boundaries?
I assume because nobody taught you proper C++. There is really no need to manually handle dynamic arrays like you do. If you would use a std::vector<std::vector<std::vector<short> > > you would get the same effect as what your code does, but without having to manage the memory yourself. Also, you can use the vector's at member function to enforce bounds checking.
An even better solution might be to use boost::multi_array, if you are willing to learn how to use it.
-
Re: 3D array memory allocation dimensions
Quote:
Originally Posted by
Kositch
Thanks for explanation, but why i am making memory allocation, when i can read from array also out of its boundaries?
I don't quite understand your question.
Reading and writing beyond the boundaries of an array leaves the behaviour of the program undefined. You're asking "how come I can do this in C++", and I answered already -- C++ does not check for array accesses being out of bounds.
Quote:
So my code is right and it allocates only memory that i need?
There are container classes, as mentioned previously, where you do not need to handle the memory yourself. For example, std::vector.
As far as your current code goes, there are much better ways of handling the memory. Please take a look:
Code:
double***Create3DArray(int height, int width, int depth)
{
double ***p3DArray = new double**[height];
double **data1 = new double*[height * width];
double *data2 = new double[ height * width * depth];
for (int i = 0; i < height; ++i, data1 += width)
{
p3DArray[i] = data1;
for (int j = 0; j < width; ++j, data2 += depth)
p3DArray[i][j] = data2;
}
return p3DArray;
}
void Free3DArray(double ***array3d)
{
// you fill this in to release the memory
}
int main(int argc, _TCHAR* argv[])
{
double ***myArray = Create3DArray(512, 512, 2);
myArray[0][2][4] = 59; // for example
Free3DArray(myArray);
return 0;
}
Note that there are only 3 calls to "new", regardless of the width, height, and depth. The trick is to allocate all of the memory for the array, and then point the pointers into the pool of memory correctly. Similarly, it only takes 3 calls to "delete[]". I didn't show this to you, since this looks like a homework assignment.
As to your current code, it makes height*width + 1 calls to "new". That can seriously fragment the heap as well as slow down the creation of the array.
Imagine if the width and height were 500. You would be making 250,001 calls to "new[]", and to release the memory, you would be making 250,001 calls to delete[]. That is way too many times to be calling the allocator. But with the code I posted, it will still do just 3 calls to "new[]".
Regards,
Paul McKenzie
-
Re: 3D array memory allocation dimensions
Quote:
Originally Posted by
Paul McKenzie
I don't quite understand your question.
Reading and writing beyond the boundaries of an array leaves the behaviour of the program undefined. You're asking "how come I can do this in C++", and I answered already -- C++ does not check for array accesses being out of bounds.
There are container classes, as mentioned previously, where you do not need to handle the memory yourself. For example, std::vector.
As far as your current code goes, there are much better ways of handling the memory. Please take a look:
Code:
double***Create3DArray(int height, int width, int depth)
{
double ***p3DArray = new double**[height];
double **data1 = new double*[height * width];
double *data2 = new double[ height * width * depth];
for (int i = 0; i < height; ++i, data1 += width)
{
p3DArray[i] = data1;
for (int j = 0; j < width; ++j, data2 += depth)
p3DArray[i][j] = data2;
}
return p3DArray;
}
void Free3DArray(double ***array3d)
{
// you fill this in to release the memory
}
int main(int argc, _TCHAR* argv[])
{
double ***myArray = Create3DArray(512, 512, 2);
myArray[0][2][4] = 59; // for example
Free3DArray(myArray);
return 0;
}
Note that there are only 3 calls to "new", regardless of the width, height, and depth. The trick is to allocate all of the memory for the array, and then point the pointers into the pool of memory correctly. Similarly, it only takes 3 calls to "delete[]". I didn't show this to you, since this looks like a homework assignment.
As to your current code, it makes height*width + 1 calls to "new". That can seriously fragment the heap as well as slow down the creation of the array.
Imagine if the width and height were 500. You would be making 250,001 calls to "new[]", and to release the memory, you would be making 250,001 calls to delete[]. That is way too many times to be calling the allocator. But with the code I posted, it will still do just 3 calls to "new[]".
Regards,
Paul McKenzie
Thanks a lot, this look better then my.
The delete part of the code will be like this?:
Code:
delete [] array3d**[height];
delete [] array3d*[height * width];
delete [] array3d[ height * width * depth];
-
Re: 3D array memory allocation dimensions
Quote:
Originally Posted by
Kositch
Thanks a lot, this look better then my.
The delete part of the code will be like this?:
Code:
delete [] array3d**[height];
delete [] array3d*[height * width];
delete [] array3d[ height * width * depth];
Actually no, but you have the right idea. The first thing is that you delete in reverse order that the data was allocated.
So you delete the pool of memory first (data2). Since the start of the pool is at array[0][0], you delete this. Then you delete where data1 starts. This is at array[0]. Then last, you delete array.
Regards,
Paul McKenzie
-
Re: 3D array memory allocation dimensions
So like that?:
Code:
delete [] array3d[0][0]
delete [] array3d[0]
delete [] array3d
I hope, it's right now :-) There will be needed no for cycles?
-
Re: 3D array memory allocation dimensions
Quote:
Originally Posted by
Kositch
So like that?:
Code:
delete [] array3d[0][0]
delete [] array3d[0]
delete [] array3d
I hope, it's right now :-) There will be needed no for cycles?
Nope, you are still missing a ton of deletes. The syntax is;
the keyword is "delete []", which will delete the array allocated at pointer. Note that at no point in time do you specify the size of the object to be deleted. You need one delete per allocation, so in your case:
Code:
for (int x = 0; x < HEIGHT; ++x)
{
for (int y = 0; y < WIDTH; ++y)
{
delete [] test[x][y];;
}
delete [] test[x];
}
delete [] test;
Just delete in the oposite order that you allocated.
EDIT: Arrays are "fun" for learning, But I highly recommend you learn to use vectors. Understanding how an array works is important, but learning to use vectors correctly is even more important.
-
Re: 3D array memory allocation dimensions
Fun about what ?
It's more dangerous to use than vector
But it looks neat: only new then delete everything seems fine after all
-
Re: 3D array memory allocation dimensions
Quote:
Originally Posted by
monarch_dodra
Nope, you are still missing a ton of deletes.
For the code I posted, the set of three deletes are correct. For the original OP's code, your code is correct.
Regards,
Paul McKenzie
-
Re: 3D array memory allocation dimensions
Quote:
Originally Posted by
Paul McKenzie
For the code I posted, the set of three deletes are correct. For the original OP's code, your code is correct.
Regards,
Paul McKenzie
Whoops. Sorry about that. Hadn't read your post in detail.
-
Re: 3D array memory allocation dimensions
Quote:
Originally Posted by
Paul McKenzie
For the code I posted, the set of three deletes are correct. For the original OP's code, your code is correct.
Regards,
Paul McKenzie
Paul, so my second try of deleting array is now right (code is above)?
-
Re: 3D array memory allocation dimensions
If you're not interested in dynamically resizing the 3D array, then the approach I would use is to wrap the whole thing in a template.
No new, no delete, copyable & assignable.
Code:
template<typename T, const size_t HEIGHT, const size_t WIDTH, const size_t DEPTH>
class Array3d
{
public:
T &operator ()(size_t x, size_t y, size_t z)
{
return (data[y + (x * WIDTH) + (z * WIDTH * HEIGHT)]);
}
const T &operator ()(size_t x, size_t y, size_t z) const
{
return (data[y + (x * WIDTH) + (z * WIDTH * HEIGHT)]);
}
private:
T data[WIDTH * HEIGHT * DEPTH];
};
int main()
{
const int HEIGHT = 2;
const int WIDTH = 3;
const int DEPTH = 4;
Array3d<short, HEIGHT, WIDTH, DEPTH> test;
for (int z = 0; z < DEPTH; z++) //filling it with ones
{
for (int y = 0; y < WIDTH; y++)
{
for (int x = 0; x < HEIGHT; x++)
{
test(x, y, z) = 1;
}
}
}
}
-
Re: 3D array memory allocation dimensions
Quote:
Originally Posted by
Kositch
Paul, so my second try of deleting array is now right (code is above)?
Yes.
Regards,
Paul McKenzie
-
Re: 3D array memory allocation dimensions
Thank you for all your patience and help!
-
Re: 3D array memory allocation dimensions
If the array doesn't have to be a tree, then here is an example of a simple dynamic multiarray of any length
Code:
#include <iostream>
#include <algorithm>
#include <functional>
#include <numeric>
#include <vector>
namespace demo
{
std::ostream& os = std::cout;
template <typename T_, const unsigned S_>
struct array
{
typedef std::vector<T_> dimension;
typedef typename dimension::size_type size_type;
typedef size_type initializer_list[S_];
template <typename Initializer_>
explicit array(const Initializer_& i, const T_& v = T_())
:
m_dim(i, i + S_),
m_array(std::accumulate(m_dim.begin(), m_dim.end(),
1, std::multiplies<size_type>()), v)
{
}
// example methods
array& operator=(const size_type i)
{
m_array.at(calculate_pos()) = i;
return *this;
}
array& operator[](const size_type i)
{
m_seq.push_back(i);
return *this;
}
operator T_&()
{
return m_array.at(calculate_pos());
}
// others ...
private:
const size_type calculate_pos()
{
dimension i(m_seq);
m_seq.clear();
return std::inner_product(i.begin(), i.end(), m_dim.begin(), 0,
std::plus<size_type>(), std::modulus<size_type>());
}
dimension m_seq;
dimension m_dim;
dimension m_array;
};
} // end namespace
int main()
{
{
using namespace demo;
array<int, 7>::initializer_list a = {4, 2, 3, 5 ,3, 2, 2};
// pass a plain array,
// or overload ctor to use [][][]... intiailizer syntax
array<int, 7> arr(a, 666);
arr[0][0][0][0][0][0][0] = 100;
arr[3][1][2][4][2][1][1] = 1000;
os << arr[0][0][0][0][0][0][0] << " "
<< arr[2][1][1][4][2][0][0];
}
}
EDIT:
No range checking has been provided on this example!
EDIT2:
calculate_pos() looks wrong but too sleepy to go over it now xD
-
Re: 3D array memory allocation dimensions
-
Re: 3D array memory allocation dimensions
Bah!
Laying in bed this morning I realised that my code did nothing more than a straight array declaration! My solution was much better suited to a 3D array sized at runtime.
Never code when half asleep :blush:
Code:
template<typename T>
class Array3d
{
public:
Array3d(size_t height, size_t width, size_t depth)
: HEIGHT(height),
WIDTH(width),
DEPTH(depth),
p_data(new T[height * width * depth])
{
}
~Array3d()
{
delete[] p_data;
}
T &operator ()(size_t x, size_t y, size_t z)
{
return (data[y + (x * WIDTH) + (z * WIDTH * HEIGHT)]);
}
const T &operator ()(size_t x, size_t y, size_t z) const
{
return (data[y + (x * WIDTH) + (z * WIDTH * HEIGHT)]);
}
private:
T p_data;
const size_t HEIGHT;
const size_t WIDTH;
const size_t DEPTH;
};
int main()
{
const int HEIGHT = 2;
const int WIDTH = 3;
const int DEPTH = 4;
Array3d<short> test(HEIGHT, WIDTH, DEPTH);
for (int z = 0; z < DEPTH; z++) //filling it with ones
{
for (int y = 0; y < WIDTH; y++)
{
for (int x = 0; x < HEIGHT; x++)
{
test(x, y, z) = 1;
}
}
}
}
-
Re: 3D array memory allocation dimensions
That is a pretty nice example, but you probably want to take the filling code and make it into a public method fill(const T& fill_value); :)
And change to
Code:
private:
T* p_data;
for it to work. ;)
-
Re: 3D array memory allocation dimensions
Quote:
Originally Posted by
Xupicor
That is a pretty nice example, but you probably want to take the filling code and make it into a public method fill(const T& fill_value); :)
That depends whether you want to follow the STL convention of making algorithms separate from the containers they work on, or not.
Quote:
And change
to
Code:
private:
T* p_data;
for it to work. ;)
Doh! That what comes of posting at 6:30 in the morning, before the first mug of tea :blush:
-
Re: 3D array memory allocation dimensions
Quote:
Originally Posted by
JohnW@Wessex
That depends whether you want to follow the STL convention of making algorithms separate from the containers they work on, or not.
Fair enough. :)
Quote:
Originally Posted by
JohnW@Wessex
Doh! That what comes of posting at 6:30 in the morning, before the first mug of tea :blush:
Happens to the best of us... In untested code that is. :) But tea? Really? Hm, you made me want to drink one instead of the usual coffee. You malicious... fellow programmer! x]
-
Re: 3D array memory allocation dimensions
Quote:
Originally Posted by
Xupicor
But tea? Really?
Yes, Earl Grey.