Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C copy 3-dimensional array

I have a pointer to a 3-dimensional array, like this:

char ***_cube3d

And I am initialising it like this:

_cube3d = (char ***)malloc(size * (sizeof(char**)));
for (int i = 0; i< size; i++) {
    _cube3d[i] = (char **)malloc(size * sizeof(char*));
    for (int j = 0; j<size; j++) {
        _cube3d[i][j] = (char *)malloc(size * sizeof(char));
    }
}

Note that the array is of dynamic size, and can contain thousands of elements, so we cannot declare it as an array in advance.

Now, I want to copy all of its contents into another array, as efficiently as possible. I know the nested loop solution where we copy each element one by one, however, it seems extremely inefficient to me. Is there a way to speed this process up? C++ code is welcome, although I would prefer it in plain C, since I am planning to iterate this solution into Objective C, and I would like to avoid injecting C++ code into a clean Objective C project.

Can anyone point me in the right direction?

like image 846
csotiriou Avatar asked Mar 04 '26 11:03

csotiriou


2 Answers

Using what you already have (but fixing the first malloc with sizeof(char***))

You could copy the array by running a bunch of for loops like this:

char new_cube[side][side][side];
for(unsigned int x = 0; x < side; x++)
    for(unsigned int y = 0; y < side; y++)
        for(unsigned int z = 0; z < side; z++)
            new_cube[x][y][z] = old_cube[x][y][z];

OR:

char new_cube[side][side][side];
for(unsigned int x = 0; x < side; x++)
    for(unsigned int y = 0; y < side; y++)
        memcpy(new_cude[x][y], old_cube[x][y], sizeof(char)*side);

which might be a bit faster.

using this method you avoid using any c++(as you said you would like) and your code complexity is kept minimal.

like image 174
RamblingMad Avatar answered Mar 06 '26 02:03

RamblingMad


If you are using C.99, you can use a variable length array (VLA) to dynamically allocate your 3-dimensional array. Once side is determined, you can declare your pointer to be:

char (*cube3d_)[side][side];

And then initialize it like this:

cube3d_ = malloc(side * sizeof(*cube3d_));

Note that in C, you are not required to cast the return value of malloc(), and doing so can actually lead to undefined behavior in the worst case. Since the "cube" has been allocated as a contiguous block, it can be copied with memcpy().

C++ does not have VLA. You can use a vector to get the C++ equivalent of your multi-dynamic allocation structure:

std::vector<std::vector<std::vector<char> > >
cube3d_(side, std::vector<std::vector<char> >(side, std::vector<char>(side)));

You can then copy it using a copy constructor or an assignment.


If cube3d_ is a member variable of an object/structure, so long as your object knows the value of side, you can still use a VLA pointer to access the memory. For example:

struct Obj {
    size_t side_;
    void *cube3d_;
};

//...
size_t side = 3;

//...
Obj o;
o.side_ = side;
char (*p)[o.side_][o.side_] = malloc(o.side_ * sizeof(*p));
o.cube3d_ = p;

//...
char (*q)[o.side_][o.side_] = o.cube3d_;
q[1][2][2] = 'a';
like image 26
jxh Avatar answered Mar 06 '26 02:03

jxh