How to Initialize 3D Array in C++

How to initialize 3D array in C++

The array in your question has only one element, so you only need one value to completely initialise it. You need three sets of braces, one for each dimension of the array.

int min[1][1][1] = {{{100}}};

A clearer example might be:

int arr[2][3][4] = { { {1, 2, 3, 4}, {1, 2, 3, 4}, {1, 2, 3, 4} },
{ {1, 2, 3, 4}, {1, 2, 3, 4}, {1, 2, 3, 4} } };

As you can see, there are two groups, each containing three groups of 4 numbers.

How to initialize a 3d array in C

A string in C requires a terminator, '\0'. So a 2-character array is too small for a string with two visible characters.

It's a feature of C's string array initialization that you don't get a warning or error for doing what you do; as often in C it's assumed that you know what you're doing.

If you do:

char foo[] = "foo";

you will get a four-character array with a terminator appended automatically, but if you do

char bar[3] = "bar";

you won't get a terminator since it doesn't fit, but you will not get an error either.

To fix it, increase the third size to [3] to make room for the terminator.

Many programmers would probably implement this instead as a 2D array of character pointers, but that uses a lot more memory than your design. It does buy you simplicity though:

const char *array[2][2] = { { "AA", "BB" }, { "CC", "DD" } };

This will make the compiler put the actual character data, with terminator characters added, somewhere in memory, and array will simply be a 2x2 array of pointers to the proper locations for the start of each string.

How to initialize a 3-dimensional array

The dimension 1 is most peculiar; you also have one too many levels of braces:

double array[5][4][1]=
{
// { These braces mean what follows is meant to initialize array[0], but
// there are 5 initializers for the 4 elements in array[0], and there
// are 4 initializers for each of the 'size 1' sub-arrays which is why
// the compiler complains about too many initializers for array[0][0][0], etc.
{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,16},
{17,18,19,20}
// }
};

This would at least compile. The fully braced version would include a pair of braces around each number:

double array[5][4][1]=
{
{ { 1 }, { 2 }, { 3 }, { 4 }, },
{ { 5 }, { 6 }, { 7 }, { 8 }, },
{ { 9 }, { 10 }, { 11 }, { 12 }, },
{ { 13 }, { 14 }, { 15 }, { 16 }, },
{ { 17 }, { 18 }, { 19 }, { 20 }, },
};

That's 5 lines, with 4 sub-arrays on each line, and each sub-array contains a single number.

Fast way of initallizing a 3d array (C++)

You're not creating a 3D array. You're creating a 1D array of pointers, each pointing to a 1D array of pointers, each pointing to a 1D array of floats. That's something totally different with respect to allocation efficiency, cache locality, access efficiency etc.

It'll be much more efficient if you instead create just one array of size width * height * depth, and use index arithmetic to access it. And remember that the standard way of spelling "dynamic array" in C++ is std::vector; this is especially relevant for you since vector value-initialises all of its elements (which for float means initialising them to .0f). You can easily create something like this:

class Array3d
{
size_t height, depth;
std::vector<float> data;

public:
Array3d(size_t width, size_t height, size_t depth) :
height(height),
depth(depth),
data(width * height * depth)
{}

float& at(size_t x, size_t y, size_t z)
{ return data[x * height * depth + y * depth + z]; }

float at(size_t x, size_t y, size_t z) const
{ return data[x * height * depth + y * depth + z]; }
};

Add more functions, safety checks etc. to taste.

Reasons why this is much faster:

  • On allocation: this is just one call to the (rather expensive) dynamic allocation mechanism, instead of the width * height + height + 1 calls in the question.

  • On access: This requires a few integer operations and one pointer dereference to get to any data member. The separate-arrays mechanism requires 3 sequential memory fetches (compute and offset, retrieve pointer there, offset it, retrieve another pointer, ...).

Is there a way to initialize a 3D array like this in C++?

In the first snippet you are allocating different types

double ***dArr = NULL;
dArr = new double**[5];
// ... ^^^^^^^^
arr[i] = new double*[5]);
// ... ^^^^^^^ ^ Typo? Using () you'd initialize those pointers
arr[i][j] = new double[5]);
// ... ^^^^^^ ^ Again?

But in the second one, you are instructing the compiler to always allocate an array of 5 double *** and dereference multiple times uninitialized memory.

typedef double*** D;
D arr;
arr = *(new D[5]);
// ... ^^^^^^^^
arr[i] = **(new D[5]);
// ... ^^^^^^^^
arr[i][j] = ***(new D[5]);
// ... ^^^^^^^^

Save yourself a lot of troubles and use a std::array or a std::vector

// With fixed size known at compile time
std::array<std::array<std::array<double, 5>, 5>, 5> arr;

// Or dynamically allocated
using vec2d = std::vector<std::vector<double>>;
std::vector<vec2d> = darr(5, vec2d(5, std::vector<double>(5)));

Later you could experiment with a class wrapping a 1D vector and proper indices mapping.

C - create 3D array of ints and initialize it to zeros

First about the error in your code. Compare this:

rows = calloc(dim*dim, sizeof(int*));

to this:

for (i=0 ; i<dim ; i++) {
board[i] = rows + i*dim*dim;

The entire size of the array allocated to rows is dim*dim elements. So, already in the second iteration of this loop, you access it out of bounds. You probably meant:

for (i=0 ; i<dim ; i++) {
board[i] = rows + i*dim;

As I already mentioned in the comment, this is not a 3D array. It mimics the usage in code by using pointers and you're using a kind-of clever trick here, so you only need 3 allocations in total. This might be a good idea under the following conditions:

  • your dim is variable at runtime, so you can't know it in advance, and
  • you have to write code for compilers that don't support VLAs1) (variable-length-arrays).

If one of this conditions is not true, it's much better to use a real 3D array. If the array doesn't have to live after leaving your function and the size isn't huge, just use a simple variable with automatic storage duration like

int board[3][3][3] = { 0 }; // possibly #define the dimension

or, for a variable dim, requiring a compiler supporting VLAs

int board[dim][dim][dim] = { 0 };

If on the other hand, the array will be huge and/or you need to return it from your function, you indeed have to allocate it dynamically. Then just use the following:

int (*board)[3][3] = calloc(3, sizeof *board); // static size
int (*board)[dim][dim] = calloc(dim, sizeof *board); // dynamic case, with VLA suppport

Also note that calloc() already sets your allocated memory to 0, so no need for looping all over it.


Side notes:

  • with sizeof, prefer the expression form, so instead of writing

    int *a = calloc(5, sizeof(int));

    better write

    int *a = calloc(5, sizeof *a);

    this avoids errors when you later change the type of a.

  • always check the return value of malloc() and friends -- they might return a null pointer (e.g. when you're running out of memory).


1) VLAs don't exist in the oldest standards C89/C90 -- they were introduced in C99 as a mandatory feature, but later made optional in C11. This allows C11 compilers to omit them, which might make sense when e.g. targeting embedded systems. In practice, you can safely assume a C11 compliant compiler supports them if it isn't special purpose.

Shorthand way to initialise a 2D/3D array in C?

The initialization you use isn't standard C, it's a GCC extension (Designated Initializers).

To initialize a 3d array, use:

int array[10][10][10] = {[0 ... 9] [0 ... 9] [0 ... 9] = 42};

Demo.



Related Topics



Leave a reply



Submit