Copy 2D array using memcpy?

17,869

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];
Share:
17,869
Admin
Author by

Admin

Updated on June 15, 2022

Comments

  • Admin
    Admin 12 months

    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!

  • Admin
    Admin about 8 years
    Oh of course, can't believe I didn't realise that. Makes a lot of sense why it wasn't working now. However, I don't see a resolution short of using for loops if I still want to use this array setup?
  • Support Ukraine
    Support Ukraine about 8 years
    If height is a constant, it can be done, i.e getting a 2D array with new. But is it?
  • Support Ukraine
    Support Ukraine about 8 years
    @KieronH See stackoverflow.com/questions/936687/… for more information
  • Ben Voigt
    Ben Voigt about 8 years
    @KieronH: I edited in an approach that I think you might find useful.
  • Admin
    Admin about 8 years
    Wow, thanks! This is exactly what I was looking for!
  • UserX
    UserX almost 3 years
    Wow, that's ingenious!
  • Ayxan Haqverdili
    Ayxan Haqverdili over 2 years
    This is great. Better yet if you wrap around a Matrix class or get a library that does.