0

I have to implement a simulation on a 3D Ising lattice represented by ones and minus ones on a 3D it would be very useful if the size could be determined at runtime (for more flexibility). As there are many accesses to the entries the memory allocation should be as local as possible. If found something for a 2D array: Copy 2D array using memcpy? :

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;

and my rating is too low to comment or reply to the post. I have basically two questions about the code: 1.why is the grid defined as pointers to arrays of length = width and the the iteration takes place over an index going up to width shifting the address by height? isn't that messing up the row and column index? 2.Should I then declare an array of length=width with pointers to arrays of length=height*depthwhich would result in the following code:

int*** new3dGrid(int width, int height, int depth){
  int*** newGrid;
  newGrid = new int**[height*depth];
  newGrid[0][0] = new int[width * height * depth];
  for (int i = 1; i < width; i++){
    newGrid[i] = newGrid[i-1] + height*depth;
    for (int j=1;j<height;j++){
      newGrid[i][j]=newGrid[i][j-1]+depth;
    }
  }
  return newGrid;
}
batman567
  • 826
  • 2
  • 12
  • 23
flabons
  • 331
  • 1
  • 8

1 Answers1

0

First of all: I STRONGLY suggest you to use, when possible, standard C++ containers; in 2D case (caution: not tested)

std::vector<std::vector<GridUnit> >  gu2d (width, std::vector<GridUnit>(height));

I strongly suggest this especially if isn't absolutely clear the example that you mention.

Consider if you access at position i, j

gu2d[i][j] = GridUnit();

where, by mistake, j value is height; without realizing it, you modify gu2d[i+1][0]. If gu2d is a vector of vectors, with gu2d.at(i).at(j) you obtain bound checking and a nice exception.

  1. why is the grid defined as pointers to arrays of length = width and the iteration takes place over an index going up to width shifting the address by height?

You can see a 2D matrix as an array of width rows of cells where each row is of height cells.

So the first pointer (newGrid) has lenght width because it references width rows.

Every row has length height, so the width values referenced by newGrid are separated (shifted) by a space of height (in pointer metric).

I think you can be clearer if you read the first answer to this question

How do I declare a 2d array in C++ using new?

  1. Should I then declare an array of length=width with pointers to arrays of length=height*depth which would result in the following code

I'm not an English native speaker but it seems to me that you have chosen an unhappy order of names. I suppose you should use depth before width.

But, using your actual names (width is the dimension of the first index, height of the second, depth of the third)...

Exactly.

Your code should change

newGrid = new int**[height*depth];

width

newGrid = new int**[width];

In the 3D case, you can see newGrid as (with your choose one names) an array of width 2D matrix where the 2D matrix are array of height rows of depth cells. So every 2D matrix is of size heigth * depth.

Caution: remember to delete with

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

p.s.: sorry for my bad English

--- EDIT ---

Sorry: I haven't seen a point that is important about your hypotesis of new3dGrid: you should allocate three pointers, not two: newGrid, as int***, for size width; newGrid[0], as int** for size width * height; newGrid[0][0], as int*, for size width * height * depth. The three types of pointers need different allocated area.

I propose the different template version (caution: not tested) [corrected by Ben Voigt; thanks!]

template <typename T>
T*** new3dGrid (unsigned height, unsigned width, unsigned depth)
 {
   T*** newGrid;

   newGrid       = new T**[width];
   newGrid[0]    = new T*[width * height];
   newGrid[0][0] = new T[width * height * depth];

   for ( unsigned i = 0U ; i < width ; ++i )
    {
      if ( i > 0U )
       {
         newGrid[i]    = newGrid[i-1U]    + height;
         newGrid[i][0] = newGrid[i-1U][0] + height * depth;
       }

      for ( unsigned j = 1U ; i < height ; ++j )
         newGrid[i][j] = newGrid[i][j-1U] + depth;
    }

   return newGrid;
 }

and you should delete three pointers

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

Sorry.

max66
  • 65,235
  • 10
  • 71
  • 111
  • This line is a mistake: `newGrid[i] = newGrid[i-1U] + height * depth;`, please see my answer at https://stackoverflow.com/a/29582795/103167 – Ben Voigt Jan 25 '18 at 23:55
  • @BenVoigt - D'oh! You're right! I've mixed the code for two different levels and forgotten to initialize at level zero. Thanks. Please, can you verify if I've correctly modified my code (that is: if I've correctly copied your code)? – max66 Jan 26 '18 at 02:25
  • you've a `for` when you meant `if`, otherwise it looks ok – Ben Voigt Jan 26 '18 at 06:06