Reputation: 155
I'm able to allocate contiguous memory to allocate a 2D array in C++. I do not know how to do for a 3D array. I have already read some posts but I haven't been able to come up with a solution.
#include <iostream>
using namespace std;
int main(int argc, char **argv){
cout << "Ints have size " << sizeof(int) << endl;
int rows= 2;
int cols= 3;
int **i= new int*[rows];
int size= rows*cols;
i[0]= new int[size];
for(int j= 1; j < rows; j++) {
i[j]= &i[0][j*cols];
}
for(int j= 0; j < rows; j++) {
for(int k= 0; k < cols; k++) {
cout << j << " " << k << " " << &i[j][k] << endl;
}
}
delete[] i;
return 0;
}
Upvotes: 4
Views: 1063
Reputation: 116
If the Space you have to allocate must be contiguous it has to be allocated with a single 'new' otherwise the memory will not be contiguous.
This would look like this:
int d1 = 10; // first
int d2 = 10; // second
int d3 = 10; // third dimension
int* array3D = new int[d1 * d2 * d3];
with this you have allocated enoug space for your 3D array, now this has to be mapped to 3D.
array3D[(1*d1*d2) + (2*d2) + (3)]; // access element at 1,2,3
With this you can Map every point of this 1D array that you Allocated onto a unique point in 3D space.
As you might see this is very error prone. So you should not ever do this like that.
Dont ever use new/delete to allocate an array like this:
use std:array
or std::vector
to handle this for you.
The use of raw new/delete leads to errors, if anything was allocated with new and you forget to delete it, or you overlook something, there will be a memory leak.
void test(){
int* a = new int[20];
// do stuff with a...
if(error)
return; // oops this is a leak
delete a; // only executed if there was no error,
}
std::array
is to be used if you know how big the array has to be at compile time, and it never has to change.
std::vector
on the other hand can be used if you dont know the size at compile time, it can change while your programm is running.
std::array<int, 10> test1; // creates a fixed size array of size 10 and type int.
std::vector<int> test2(10); // creates an array that can change at runtime:
test2.push_back(2); // the vector now has size 11 and the last element is equal to 2
This way you also don't have to delete
the array at the end.
If you want to be able to use this more often in your code, it can be very helpful to wrap all this functionality in a class:
#include <array>
template<typename T, std::size_t _D1, std::size_t _D2, std::size_t _D3>
class Array3D{
std::array<T, _D1*_D2*_D3> elements;
public:
std::size_t D1(){ return _D1; }
std::size_t D2(){ return _D1; }
std::size_t D3(){ return _D1; }
T& element(std::size_t d1, std::size_t d2, std::size_t d3){
return elements[(d1*_D1*_D2) + (d2*_D2) + (d3)];
}
};
int main(){ // argc/argv not required if you dont use them
Array3D<int, 10, 10, 10> array;
array.element(1,2,3) = 5;
// loop thorug all elements
// the methods d1,d2,d3 return the dimensions you gave them initialy
// this way if you cange the array size you dont have to change this loop at all
for(std::size_t i = 0; i < array.D1(); i++)
for(std::size_t j = 0; j < array.D2(); j++)
for(std::size_t k = 0; k < array.D3(); k++)
array.element(i,j,k) = 5;
// no delete
}
Upvotes: 3
Reputation: 114461
A 3d array with P
planes, each of which has R
rows and C
columns will require P*R*C
elements. You can just allocate them at once for example with:
Element *p = new Element[P*R*C];
then to access the element at coordinates (p, r, c)
you can use as formula:
int index = (p*R + r)*C + c;
To make things readable an easy solution is to make a class
template<typename T>
struct Matrix3D {
int P, R, C;
std::vector<T> elements;
Matrix3D(int P, int R, int C)
: P(P), R(R), C(C), elements(P*R*C)
{ }
T& operator()(int p, int r, int c) {
return elements[(p*R + r)*C + c];
}
};
in this example I'm using an std::vector
to store the elements because this makes things simpler about ownership/copying and still guarantees all elements will be contiguous in memory. If you want to manually allocate the storage then more code is needed.
If the size is known at compile time then you can make P
, R
and C
template parameters and use an std::array
member instead of std::vector
. This should give some performance improvement as the whole class will end up being a single chunk of memory in the heap and allowing constant multiplication tricks for element access.
Upvotes: 7
Reputation: 1251
An array of array (3D array)
is nothing more than an array which contains a reference on an other array in each index.
You'll just have to allocate your first 2D array
, and then, for each index of this array, allocate an other array inside it.
Upvotes: 2