Pointers in C++, please help

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

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

Pointers in C++, please help

Post by Michael Sherwin »

I've spent hours in my C++ primer and other books and online with no success.

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.

Code: Select all

unsigned char *mvsQ[] = { &mvsNW[0][0], &mvsNE[0][0], &mvsSW[0][0], &mvsSE[0][0],
                          &mvsNN[0][0], &mvsEE[0][0], &mvsSS[0][0], &mvsSW[0][0] };

Code: Select all

void WSBBG(threadS *t, u08 id, u08 fs, u08 *inv, u64 *bb) {
  u08 i;
  u64 ray;

  do {
    i = FirstBit32(*inv);
    *inv ^= (1 << i);
    switch (i) {
    ...
   case NN:
      ray = (rayNN[fs] & belowInc[FirstBit64(rayNN[fs] & t->aPieces)] & ~t->wPieces);
      *bb &= andNN[fs];
       *bb |= ray; mvsNN[fs][0] = (u08)__popcnt64(ray);
      break;
  ...
      mvs = mvsQ[i];
    while (ray) {
      n++;
      ts = FirstBit64(ray);
      ray ^= one << ts;
      *(mvs + (((fs << 3) + n))) = ts; // I want to do something like,  mvs[fs][n] = ts;
    }
     *(mvs + (fs << 3)) = n;
    t->inv[t->brd[fs]][t->top[t->brd[fs]]] = 0;
  } while (*inv);
}
         
If you are on a sidewalk and the covid goes beep beep
Just step aside or you might have a bit of heat
Covid covid runs through the town all day
Can the people ever change their ways
Sherwin the covid's after you
Sherwin if it catches you you're through
Ras
Posts: 2487
Joined: Tue Aug 30, 2016 8:19 pm
Full name: Rasmus Althoff

Re: Pointers in C++, please help

Post by Ras »

If you have this:

Code: Select all

*(mvs + (((fs << 3) + n))) = ts; // I want to do something like,  mvs[fs][n] = ts;
then the shift suggests that the n variable stretches over 3 bit, i.e. it can go from 0 to 7. That means a lower array dimenion of 8. Assuming that the other dimension is also 8 because it is about a chessboard:

Code: Select all

TYPE_T mvs[8][8];
mvs[fs][n] = ts;
...
mvs[fs][0] = n; /*use a proper constant/define for 0 to avoid the magic number 0 here!*/
However, this would be idiomatic C code. In modern C++, dealing with raw pointers is usually regarded as bad practice.
Rasmus Althoff
https://www.ct800.net
Michael Sherwin
Posts: 3196
Joined: Fri May 26, 2006 3:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: Pointers in C++, please help

Post by Michael Sherwin »

Ras wrote: Sat Apr 20, 2019 9:08 pm If you have this:

Code: Select all

*(mvs + (((fs << 3) + n))) = ts; // I want to do something like,  mvs[fs][n] = ts;
then the shift suggests that the n variable stretches over 3 bit, i.e. it can go from 0 to 7. That means a lower array dimenion of 8. Assuming that the other dimension is also 8 because it is about a chessboard:

Code: Select all

TYPE_T mvs[8][8];
mvs[fs][n] = ts;
...
mvs[fs][0] = n; /*use a proper constant/define for 0 to avoid the magic number 0 here!*/
However, this would be idiomatic C code. In modern C++, dealing with raw pointers is usually regarded as bad practice.
Hi Ras, Thanks! How would it be done with good practice in C++? I have no clue.
If you are on a sidewalk and the covid goes beep beep
Just step aside or you might have a bit of heat
Covid covid runs through the town all day
Can the people ever change their ways
Sherwin the covid's after you
Sherwin if it catches you you're through
Ras
Posts: 2487
Joined: Tue Aug 30, 2016 8:19 pm
Full name: Rasmus Althoff

Re: Pointers in C++, please help

Post by Ras »

Michael Sherwin wrote: Sat Apr 20, 2019 9:20 pmHi Ras, Thanks! How would it be done with good practice in C++? I have no clue.
You'd use some of the STL provided types. You could use either a std::vector inside another std::vector, or std::array inside another std::array. I think the latter will be faster here because the dimensions are fixed so that the flexibility of std::vector is not needed here.

Code: Select all

std::array<std::array<int, 3>, 2> my_matrix {{
    {{0, 1, 2}},
    {{3, 4, 5}}
 }};

my_matrix[1][2] = 42;
However, you should benchmark whether that is slower than directly using pointers.
Rasmus Althoff
https://www.ct800.net
Michael Sherwin
Posts: 3196
Joined: Fri May 26, 2006 3:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: Pointers in C++, please help

Post by Michael Sherwin »

Ras wrote: Sat Apr 20, 2019 9:43 pm
Michael Sherwin wrote: Sat Apr 20, 2019 9:20 pmHi Ras, Thanks! How would it be done with good practice in C++? I have no clue.
You'd use some of the STL provided types. You could use either a std::vector inside another std::vector, or std::array inside another std::array. I think the latter will be faster here because the dimensions are fixed so that the flexibility of std::vector is not needed here.

Code: Select all

std::array<std::array<int, 3>, 2> my_matrix {{
    {{0, 1, 2}},
    {{3, 4, 5}}
 }};

my_matrix[1][1] = 42;
However, you should benchmark whether that is slower than directly using pointers.
Thanks again! If I can understand it I'll give it a try. I have the, C++ Programming Language, by Bjarne Stroustrup. Maybe std::array will be in there. :D
If you are on a sidewalk and the covid goes beep beep
Just step aside or you might have a bit of heat
Covid covid runs through the town all day
Can the people ever change their ways
Sherwin the covid's after you
Sherwin if it catches you you're through
odomobo
Posts: 96
Joined: Fri Jul 06, 2018 1:09 am
Location: Chicago, IL
Full name: Josh Odom

Re: Pointers in C++, please help

Post by odomobo »

BTW, std::array should have the same performance as a normal array. The purpose of having std::array in the language (as I understand it) is providing a strong type to represent an array (i.e. it won't decay to a pointer) and provides additional features (i.e. runtime bounds checking with .at() ). Otherwise, it should provide 0 runtime overhead over a normal array, as it should compile down to the same machine code (as long as you use index operator [] instead of .at() ). Of course, the compiler won't necessarily do as it's supposed to, so benchmarking is king
Michael Sherwin
Posts: 3196
Joined: Fri May 26, 2006 3:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: Pointers in C++, please help

Post by Michael Sherwin »

odomobo wrote: Tue Apr 30, 2019 6:04 pm BTW, std::array should have the same performance as a normal array. The purpose of having std::array in the language (as I understand it) is providing a strong type to represent an array (i.e. it won't decay to a pointer) and provides additional features (i.e. runtime bounds checking with .at() ). Otherwise, it should provide 0 runtime overhead over a normal array, as it should compile down to the same machine code (as long as you use index operator [] instead of .at() ). Of course, the compiler won't necessarily do as it's supposed to, so benchmarking is king
I looked into std::array. " it won't decay to a pointer" As best I can tell is this means that even when passing a standard array by reference the compiler is smart enough to allow array notation rather than having to use pointer arithmetic. That is just a guess because it really did not say that explicitly. So concerning my original question, how do I use std::array to load a pointer from an array of pointers and then use that pointer as it were an array name? I do not see the connection.
If you are on a sidewalk and the covid goes beep beep
Just step aside or you might have a bit of heat
Covid covid runs through the town all day
Can the people ever change their ways
Sherwin the covid's after you
Sherwin if it catches you you're through
odomobo
Posts: 96
Joined: Fri Jul 06, 2018 1:09 am
Location: Chicago, IL
Full name: Josh Odom

Re: Pointers in C++, please help

Post by odomobo »

Can you post the declaration for mvsNW? Then I can walk you through it. it shouldn't require std::array to get this to work the way you want.

Decaying to a pointer doesn't actually affect you right now, but I can show you an example:

Code: Select all

void foo()
{
    int arr[10];
    // ...
    bar(arr); // this works; int array arr decays to an int pointer
    
    std::array<int, 10> arr2;
    // ...
    bar(arr2); // compile-time error
}

void bar(int *arr)
{
    // ...
}
Michael Sherwin
Posts: 3196
Joined: Fri May 26, 2006 3:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: Pointers in C++, please help

Post by Michael Sherwin »

odomobo wrote: Tue Apr 30, 2019 8:04 pm Can you post the declaration for mvsNW? Then I can walk you through it. it shouldn't require std::array to get this to work the way you want.

Decaying to a pointer doesn't actually affect you right now, but I can show you an example:

Code: Select all

void foo()
{
    int arr[10];
    // ...
    bar(arr); // this works; int array arr decays to an int pointer
    
    std::array<int, 10> arr2;
    // ...
    bar(arr2); // compile-time error
}

void bar(int *arr)
{
    // ...
}

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.
u08 mvsNW[64][8];
u08 mvsNE[64][8];
u08 mvsSE[64][8];
u08 mvsSW[64][8];

// This is an array of pointers to the above arrays.
unsigned char *mvsB[] = { &mvsNW[0][0], &mvsNE[0][0], &mvsSW[0][0], &mvsSE[0][0] };

// 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++) { ptr = mvsB[i];
    for (u08 j = 1; j <= *(ptr + (m->fs << 3)); j++) {
      m->ts = *(ptr + ((m->fs << 3) + 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);
    }
  }
}

If you are on a sidewalk and the covid goes beep beep
Just step aside or you might have a bit of heat
Covid covid runs through the town all day
Can the people ever change their ways
Sherwin the covid's after you
Sherwin if it catches you you're through
odomobo
Posts: 96
Joined: Fri Jul 06, 2018 1:09 am
Location: Chicago, IL
Full name: Josh Odom

Re: Pointers in C++, please help

Post by odomobo »

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