Обычная старая декларация (не делайте этого):
try
{
float *** f = new float ** [2];
for (size_t i = 0; i < 2; i++)
{
f[i] = new float * [3];
for (size_t j = 0; j < 3; j++)
f[i][j] = new float[4];
}
} catch(const std::exception & e) { /* This is a pain to deal with to avoid any leak */ }
// Now you can access via f[0][1][2]
// delete[] in reverse order.
Немного лучше (избегайте использования большого количества выделений):
try
{
typedef float BigArray[3][4];
BigArray * f = new BigArray[2];
} catch(const std::exception & e) { /* here it's simple */ }
// delete with delete[] f
Немного громоздко, но вас больше не волнует утечка памяти:
std::vector<std::vector<std::vector<float>>> f(2, std::vector<std::vector<float>>(3, std::vector<float>(4)));
// Use with f[0][1][2]
Кроме того, как многие сказали бы, вместо указателя на указатель на указатель с плавающей точкой, вместо этого вы должны хранить свой массив в указателе на float, это будет намного эффективнее, так как вам не нужно разыменовывать в 3 шага чтобы получить доступ к элементу, например:
int vectorElems = 4, columns = 3, rows = 2;
int rowStride = vectorElems * columns;
float * f = new float[rows*columns*vectorElems];
// Access with stride:
f[0 * rowStride + 1 * vectorElems + 2] = 3.14f;
// Delete with delete[] f
Существуют также классы матрицы шаблонов (например, в opencv), которые делают это правильно, предоставляя перегруженный оператор (), чтобы вы могли получить доступ к объекту, например f(0, 1, 2)