Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Copy 2D array using memcpy?

Tags:

c++

arrays

memcpy

So I want to copy the contents of a 2D array to another array of the exact same type. Here is how the array is created:

 GridUnit** newGrid;
 newGrid = new GridUnit*[width];
    for (int i = 0; i < width; i++)
        newGrid[i] = new GridUnit[height];

GridUnit is size 16 (4 floats). So that's all initialised fine, no problems with using it as it is after I have ran the for loops to actually fill the values with some data. Now what I want to do is copy the contents of another array into this one (without for loops if possible). This is what I have been trying to do so far:

 memcpy(&newGrid, &grid, height * width * 16);

'grid' is identical to 'newGrid' in terms of its size and type. However, this does not work. I know the memcpy is possibly not correct, but having tried multiple different setups using this, I don't know what's going wrong with it anymore, so any help would be welcome!

like image 908
KieronH Avatar asked Mar 31 '15 18:03

KieronH


1 Answers

If you actually had a 2-D array, that memcpy call would work. But you don't, you have width separate discontiguous 1-D arrays, collected in an array of pointers.

It is possible to dynamically allocate a contiguous block where row and column count both vary at runtime, and preserve the two-subscript access. You'll have to change the allocation code as follows:

GridUnit** newGrid;
newGrid = new GridUnit*[width];
newGrid[0] = new GridUnit[width * height];
for (int i = 1; i < width; i++)
    newGrid[i] = newGrid[i-1] + height;

Deallocation becomes simpler:

delete[] newGrid[0];
delete[] newGrid;

There's no delete[] for newGrid[i] with i > 0 because they don't have their own blocks, they just point into the single large block. Because everything is contiguous, you can think of newGrid[0] either as a pointer to the first row (height elements), or the entire 2-D array (width * height elements).

And you can then access all the data as a single contiguous block:

memcpy(newGrid[0], oldGrid[0], height * width * sizeof newGrid[0][0]);

Of course, one shouldn't use raw pointers for memory ownership. A smart pointer will ensure the memory is properly deleted even with exceptional flow control. It would look like this:

std::unique_ptr<GridUnit[]> newData;
std::unique_ptr<GridUnit*[]> newGrid;
// before C++14 use // newData.reset(new GridUnit[width * height]);
newData = std::make_unique<GridUnit[]>(width * height);
// before C++14 use // newGrid.reset(new GridUnit*[width]);
newGrid = std::make_unique<GridUnit*[]>(width);
for (int i = 0; i < width; i++)
    newGrid[i] = &newData[i * height];
like image 62
Ben Voigt Avatar answered Nov 04 '22 13:11

Ben Voigt