Pointers in C++, please help

Discussion of chess software programming and technical issues.

Moderators: hgm, Harvey Williamson, bob

Forum rules
This textbox is used to restore diagrams posted with the [d] tag before the upgrade.
Michael Sherwin
Posts: 3024
Joined: Fri May 26, 2006 1:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: Pointers in C++, please help

Post by Michael Sherwin » Tue Apr 30, 2019 8:10 pm

odomobo wrote:
Tue Apr 30, 2019 7:01 pm
Actually, something I just realized is that c++ doesn't like the notation for pointers to normal arrays, so std::array will help us out here. Maybe there's a way to do it, but if so it's beyond me.

Code: Select all

// These are vectors for the bishop. Ex: mvsNW[A1][0] is the number of squares. [A1][1-7] are the to squares.
// Note that we have to declare the dimensions in reverse order, since we're explicitly nesting the types
std::array<std::array<u08, 8>, 64> mvsNW;
std::array<std::array<u08, 8>, 64> mvsNE;
std::array<std::array<u08, 8>, 64> mvsSE;
std::array<std::array<u08, 8>, 64> mvsSW;

// This is an array of pointers to the above arrays.
// Note that this is storing the exact same pointer as befores, but now it's preserving type information.
// We could have mvsB itself be a std::array, but it's not necessary.
std::array<std::array<u08, 8>, 64> * mvsB[] = { &mvsNW, &mvsNE, &mvsSW, &mvsSE };

// In this code I declare unsigned char *ptr and in line 4 it is assigned each array address by a for loop
// Then It is used with pointer arithmetic. But, I thought it would be possible to use it as an array name as in ptr[fs][j]
void WBf(threadS *t, u08 id, u08 depth, moveS *m) {
  unsigned char *ptr = &t->inv[id][t->top[id]];  m->fs = t->sqr[id];
  if (*ptr) WSBBG(t, id, m->fs, ptr, &t->stk[id][t->top[id]]);
  for (u08 i = 0; i < 4; i++) { 
    // Why are we dereferencing, and then holding a reference to the underlying array object? Why not leave it as a pointer?
    // Because otherwise we'd need to explicitly deference like this:
    // (*mvs)[m->fs][j]
    // BTW, if we just dereferenced, but didn't hold a reference, semantically we're asking the compiler to copy the contents of the array onto the stack.
    auto & mvs = *mvsB[i];
    for (u08 j = 1; j <= mvs[m->fs][0]; j++) {
      m->ts = mvs[m->fs][j];
      m->id = t->brd[m->ts];
      m->typ = (m->id) ? WBC : WBM;
      MakeMove(t, m);
      if (depth > 0) Perft(t, depth - 1);
      TakeBack(t, m);
    }
  }
}
Let me know if you have any questions
Yes that is what I was looking for, ty.

"(*mvs)[m->fs][j]"

I believe that this notation is what I could not remember.

However, if it works, I like the std::array as it is very precise and writing "mvs[m->fs][0]" is so much more natural than writing "*(ptr + ((m->fs << 3) + j))". And of course less error prone.

If it is possible with natural arrays I'm thinking maybe a typedef can be used.

typedef unsigned char array[64][8];

array *mvsB [] = { &mvsNW, ...

array * mvs = mvsB;

Or something close. Because something similar works for functions!

typedef void MGt(threadS *, u08 id, u08 depth, moveS *);

MGt WPf, WNf, WBf, WRf, WQf, WKf, WSf, WLf, BPf, BNf, BBf, BRf, BQf, BKf, BSf, BLf;

MGt *MGf[] = { WPf, WPf, WNf, WBf, WRf, WQf, WKf, WSf, WLf, BPf, BPf, BNf, BBf, BRf, BQf, BKf, BSf, BLf };

void Perft(threadS *t, u08 depth) {
u08 id = t->wtm ? 19 : 39, typ;

id = t->nxt[id];
do {
typ = t->typ[id];
MGf[typ](t, id, depth, &t->moves[t->ply]);
} while ((id = t->nxt[id]));
}

But, idk and my intuition is not always right.
I hate if statements. Pawns demand if statements. Therefore I hate pawns.

odomobo
Posts: 59
Joined: Thu Jul 05, 2018 11:09 pm
Location: Chicago, IL
Full name: Josh Odom

Re: Pointers in C++, please help

Post by odomobo » Tue Apr 30, 2019 9:11 pm

I played around with it, and figured out how to do it with a natural array. However, I personally find the notation more confusing.

Code: Select all

u08 mvsNW[64][8];
//...

u08 (*mvsB[])[64][8] = { &mvsNW, &mvsNE, &mvsSW, &mvsSE };

// ...

auto & mvs = *mvsB[i];
m->ts = mvs[m->fs][j];
I also found another way to do this, since pointers in c/c++ can be indexed like arrays, and since the size of the [64] dimension of mvsNW isn't necessary to perform a lookup into the table. I also find this to be somewhat confusing.

Code: Select all

u08 mvsNW[64][8];
//...

u08 (*mvsB[])[8] = { &mvsNW[0], &mvsNE[0], &mvsSW[0], &mvsSE[0] };

// ...

u08 (*mvs)[8] = mvsB[i]; // can instead use auto; I am just showing the type here, which is a pointer to u08[8]
m->ts = mvs[m->fs][j];
Finally, you could do the last one using std::array instead of native arrays. I trust you can figure out how to do that.

Ultimately, it shouldn't matter which way you do it, as long as you don't accidentally copy a bunch of data to the stack.

Michael Sherwin
Posts: 3024
Joined: Fri May 26, 2006 1:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: Pointers in C++, please help

Post by Michael Sherwin » Tue Apr 30, 2019 9:22 pm

odomobo wrote:
Tue Apr 30, 2019 9:11 pm
I played around with it, and figured out how to do it with a natural array. However, I personally find the notation more confusing.

Code: Select all

u08 mvsNW[64][8];
//...

u08 (*mvsB[])[64][8] = { &mvsNW, &mvsNE, &mvsSW, &mvsSE };

// ...

auto & mvs = *mvsB[i];
m->ts = mvs[m->fs][j];
I also found another way to do this, since pointers in c/c++ can be indexed like arrays, and since the size of the [64] dimension of mvsNW isn't necessary to perform a lookup into the table. I also find this to be somewhat confusing.

Code: Select all

u08 mvsNW[64][8];
//...

u08 (*mvsB[])[8] = { &mvsNW[0], &mvsNE[0], &mvsSW[0], &mvsSE[0] };

// ...

u08 (*mvs)[8] = mvsB[i]; // can instead use auto; I am just showing the type here, which is a pointer to u08[8]
m->ts = mvs[m->fs][j];
Finally, you could do the last one using std::array instead of native arrays. I trust you can figure out how to do that.

Ultimately, it shouldn't matter which way you do it, as long as you don't accidentally copy a bunch of data to the stack.
8-) Thanks!
I hate if statements. Pawns demand if statements. Therefore I hate pawns.

User avatar
lucasart
Posts: 3035
Joined: Mon May 31, 2010 11:29 am
Full name: lucasart
Contact:

Re: Pointers in C++, please help

Post by lucasart » Wed May 01, 2019 5:10 am

Michael Sherwin wrote:
Tue Apr 30, 2019 9:22 pm
odomobo wrote:
Tue Apr 30, 2019 9:11 pm
I played around with it, and figured out how to do it with a natural array. However, I personally find the notation more confusing.

Code: Select all

u08 mvsNW[64][8];
//...

u08 (*mvsB[])[64][8] = { &mvsNW, &mvsNE, &mvsSW, &mvsSE };

// ...

auto & mvs = *mvsB[i];
m->ts = mvs[m->fs][j];
I also found another way to do this, since pointers in c/c++ can be indexed like arrays, and since the size of the [64] dimension of mvsNW isn't necessary to perform a lookup into the table. I also find this to be somewhat confusing.

Code: Select all

u08 mvsNW[64][8];
//...

u08 (*mvsB[])[8] = { &mvsNW[0], &mvsNE[0], &mvsSW[0], &mvsSE[0] };

// ...

u08 (*mvs)[8] = mvsB[i]; // can instead use auto; I am just showing the type here, which is a pointer to u08[8]
m->ts = mvs[m->fs][j];
Finally, you could do the last one using std::array instead of native arrays. I trust you can figure out how to do that.

Ultimately, it shouldn't matter which way you do it, as long as you don't accidentally copy a bunch of data to the stack.
8-) Thanks!
Instead of looking for complicated solutions to an artificial problem, you should rethink your code, in such a way that a normal C array can be used (C arrays can be multidimensional).
Theory and practice sometimes clash. And when that happens, theory loses. Every single time.

Michael Sherwin
Posts: 3024
Joined: Fri May 26, 2006 1:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: Pointers in C++, please help

Post by Michael Sherwin » Wed May 01, 2019 6:14 am

lucasart wrote:
Wed May 01, 2019 5:10 am
Michael Sherwin wrote:
Tue Apr 30, 2019 9:22 pm
odomobo wrote:
Tue Apr 30, 2019 9:11 pm
I played around with it, and figured out how to do it with a natural array. However, I personally find the notation more confusing.

Code: Select all

u08 mvsNW[64][8];
//...

u08 (*mvsB[])[64][8] = { &mvsNW, &mvsNE, &mvsSW, &mvsSE };

// ...

auto & mvs = *mvsB[i];
m->ts = mvs[m->fs][j];
I also found another way to do this, since pointers in c/c++ can be indexed like arrays, and since the size of the [64] dimension of mvsNW isn't necessary to perform a lookup into the table. I also find this to be somewhat confusing.

Code: Select all

u08 mvsNW[64][8];
//...

u08 (*mvsB[])[8] = { &mvsNW[0], &mvsNE[0], &mvsSW[0], &mvsSE[0] };

// ...

u08 (*mvs)[8] = mvsB[i]; // can instead use auto; I am just showing the type here, which is a pointer to u08[8]
m->ts = mvs[m->fs][j];
Finally, you could do the last one using std::array instead of native arrays. I trust you can figure out how to do that.

Ultimately, it shouldn't matter which way you do it, as long as you don't accidentally copy a bunch of data to the stack.
8-) Thanks!
Instead of looking for complicated solutions to an artificial problem, you should rethink your code, in such a way that a normal C array can be used (C arrays can be multidimensional).
Yes, a three dimensional array could be used, mvs[8][64][8], as in, ts = mvs[ray][fs][n]. But that would always require three dimensional math to access the array. For some operations that would be slow. For example the test for queenside castling to see if the squares between the rook and the king are empty would be this:

if ( mvsEE[A1][0] == 3 ) {
// all the squares between A1 and E1 are empty
}

Do you really want me to add a third index to all such things, in a chess engine?

EDIT: That actually is not a correct example. However, the principle is valid. Bed time. :)
I hate if statements. Pawns demand if statements. Therefore I hate pawns.

odomobo
Posts: 59
Joined: Thu Jul 05, 2018 11:09 pm
Location: Chicago, IL
Full name: Josh Odom

Re: Pointers in C++, please help

Post by odomobo » Wed May 01, 2019 1:03 pm

lucasart is right. Instead of an array of a pointer of 2d arrays, you're better off having a single 3d array. There are techniques you can use such that this will strictly be more efficient, never less efficient.

Code: Select all

u08 mvsB[][64][8];

// references to sub-arrays
u08 (&mvsNW)[64][8] = mvsB[0];
u08 (&mvsNE)[64][8] = mvsB[1];
// ...

void WBf(threadS *t, u08 id, u08 depth, moveS *m) {
  unsigned char *ptr = &t->inv[id][t->top[id]];  m->fs = t->sqr[id];
  if (*ptr) WSBBG(t, id, m->fs, ptr, &t->stk[id][t->top[id]]);
  for (u08 i = 0; i < 4; i++) { 
    auto & mvs = mvsB[i];
    for (u08 j = 1; j <= mvs[m->fs][0]; j++) {
      m->ts = mvs[m->fs][j];
      m->id = t->brd[m->ts];
      m->typ = (m->id) ? WBC : WBM;
      MakeMove(t, m);
      if (depth > 0) Perft(t, depth - 1);
      TakeBack(t, m);
    }
  }
}
When you take a reference to a sub-array like this, the machine code is really storing a pointer to the first index in that sub-array.

Michael Sherwin
Posts: 3024
Joined: Fri May 26, 2006 1:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: Pointers in C++, please help

Post by Michael Sherwin » Wed May 01, 2019 7:08 pm

odomobo wrote:
Wed May 01, 2019 1:03 pm
lucasart is right. Instead of an array of a pointer of 2d arrays, you're better off having a single 3d array. There are techniques you can use such that this will strictly be more efficient, never less efficient.

Code: Select all

u08 mvsB[][64][8];

// references to sub-arrays
u08 (&mvsNW)[64][8] = mvsB[0];
u08 (&mvsNE)[64][8] = mvsB[1];
// ...

void WBf(threadS *t, u08 id, u08 depth, moveS *m) {
  unsigned char *ptr = &t->inv[id][t->top[id]];  m->fs = t->sqr[id];
  if (*ptr) WSBBG(t, id, m->fs, ptr, &t->stk[id][t->top[id]]);
  for (u08 i = 0; i < 4; i++) { 
    auto & mvs = mvsB[i];
    for (u08 j = 1; j <= mvs[m->fs][0]; j++) {
      m->ts = mvs[m->fs][j];
      m->id = t->brd[m->ts];
      m->typ = (m->id) ? WBC : WBM;
      MakeMove(t, m);
      if (depth > 0) Perft(t, depth - 1);
      TakeBack(t, m);
    }
  }
}
When you take a reference to a sub-array like this, the machine code is really storing a pointer to the first index in that sub-array.
Okay I understand pointers to subarrays although the syntax is baffling. In your example I see each vector being used separately as in an unrolled loop.

Where in this, auto & mvs = mvsB[n]; Does the compiler care about the variable name mvsNW? :?
I hate if statements. Pawns demand if statements. Therefore I hate pawns.

User avatar
phhnguyen
Posts: 355
Joined: Wed Apr 21, 2010 2:58 am
Location: Australia
Full name: Nguyen Hong Pham
Contact:

Re: Pointers in C++, please help

Post by phhnguyen » Wed May 01, 2019 10:08 pm

Michael Sherwin wrote:
Sat Apr 20, 2019 6:58 pm
I want to use a pointer to a two dimensional array like it was an array name. This code works and I am okay with that but it uses pure pointer arithmetic, however, for readability I want to use the pointer like array notation instead.
Whenever I want to pass complicated parameters, say, (too) many ones, one or some multi dimensional arrays,... I may group them together and put in a class or a structure then pass it. That is cheap, quick and much easier to maintain. It can help to avoid some errors (e.g. call functions with wrong order paramters) too.

Code: Select all

class MyData {
public:
  int a, b, c;
  int64_t d, e;
  char *array[20][40];
};

void MyClass::myfunction(MyData& data) 
{
   auto ch = data.array[2][7];
   ...
}
https://github.com/nguyenpham/Banksia
An open source C++11 chess tournament manager

Post Reply