Silly C Question

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

GothicChessInventor

Silly C Question

Post by GothicChessInventor »

I can't believe I am having difficulty with this... one of those syntax things that is just bugging me.

I have many global pointers (over 100) to unsigned char data that I malloced. Each element is a "distance to win" in plies, just 0 for an immediate loss, 1 for mate in 1, 2 for mated in 2, 3 for mate in 3, etc.

Looks like this

unsigned char *g_tablebase_01;
unsigned char *g_tablebase_02;
unsigned char *g_tablebase_03;
unsigned char *g_tablebase_04;

They are initialized in a routine such as:

g_tablebase_01 = (unsigned char *)malloc(bytes_needed_01);
g_tablebase_02 = (unsigned char *)malloc(bytes_needed_02);
g_tablebase_03 = (unsigned char *)malloc(bytes_needed_03);

where bytes_needed_01, bytes_needed_02, etc are values I can compute depending on the size of the tablebase.

I would like to have just one routine to set the UNKNOWN values to draws at the end. Right now I am doing it the lazy way, with a separate routine for each tablebase

Code: Select all

switch(which_tb)
{
	case 1: 
	for&#40;i = 0; i < how_many_positions; i++)
	&#123;
		tb_value = g_tablebase_01&#91;i&#93;; 
		if&#40;tb_value == DB_UNKNOWN_THAT_FITS_INTO_8_BITS&#41;
		&#123;
			g_tablebase_01&#91;i&#93; = TB_DRAW;
		&#125;
	&#125;
	break;
	case 2&#58; 
	for&#40;i = 0; i < how_many_positions; i++)
	&#123;
		tb_value = g_tablebase_02&#91;i&#93;; 
		if&#40;tb_value == DB_UNKNOWN_THAT_FITS_INTO_8_BITS&#41;
		&#123;
			g_tablebase_02&#91;i&#93; = TB_DRAW;
		&#125;
	&#125;
	break;
&#125;
It would be very convenient to do it by passing in the global pointer from an external calling function, and have the internal function manipulate the global pointer through the local variable. This would involve passing the address of the global pointer, and having the internal function use a pointer to the pointer, but this is getting barfed all over...

Code: Select all

void set_db_unknowns_to_draw&#40;unsigned char **your_pointer, unsigned long total_positions&#41;
&#123;
   unsigned long i;
	for&#40;i = 0; i < total_positions; i++)
	&#123;
		db_value = *&#40;your_pointer&#91;i&#93;);
		if&#40;db_value == TB_UNKNOWN&#41;
		&#123;
			*&#40;your_pointer&#91;i&#93;) = TB_DRAW;
		&#125;
	&#125;
&#125;
The problem is that the global pointers aren't updated, and I think passing (& g_tablebase_01) as a parameter isn't getting the job done. It's been a while since I even owned a C book.

Anybody remember how to do this "C 101" thing?

Thanks in advance.
TonyJH
Posts: 183
Joined: Tue Jun 20, 2006 4:41 am
Location: USA

Re: Silly C Question

Post by TonyJH »

If I'm understanding correctly, the code would make more sense to me if you replaced "*(your_pointer)" with "(*your_pointer)".

However, it seems like this would also be doable (and simpler) just using pointers instead of pointers to pointers.
User avatar
Zach Wegner
Posts: 1922
Joined: Thu Mar 09, 2006 12:51 am
Location: Earth

Re: Silly C Question

Post by Zach Wegner »

GothicChessInventor wrote:unsigned char *g_tablebase_01;
unsigned char *g_tablebase_02;
unsigned char *g_tablebase_03;
unsigned char *g_tablebase_04;
http://en.wikipedia.org/wiki/Array#In_computer_science

Code: Select all

void set_db_unknowns_to_draw&#40;unsigned char **your_pointer, unsigned long total_positions&#41;
&#123;
   unsigned long i;
	for&#40;i = 0; i < total_positions; i++)
	&#123;
		db_value = *&#40;your_pointer&#91;i&#93;);
		if&#40;db_value == TB_UNKNOWN&#41;
		&#123;
			*&#40;your_pointer&#91;i&#93;) = TB_DRAW;
		&#125;
	&#125;
&#125;

Code: Select all

void set_db_unknowns_to_draw&#40;unsigned char *your_pointer, unsigned long total_positions&#41;
&#123;
   unsigned long i;
	for&#40;i = 0; i < total_positions; i++)
	&#123;
		db_value = your_pointer&#91;i&#93;;
		if&#40;db_value == TB_UNKNOWN&#41;
		&#123;
			your_pointer&#91;i&#93; = TB_DRAW;
		&#125;
	&#125;
&#125;
GothicChessInventor

Re: Silly C Question

Post by GothicChessInventor »

That only updates the LOCAL variable, not the GLOBAL variable passed in. I know how to do what you have shown.

Consider this as a restatement of the problem:

Code: Select all

unsigned char *g_tb_X_versus_Y;
unsigned char *g_tb_Y_versus_Z;
unsigned char *g_tb_X_versus_Z;

#define UNKNOWN 255
#define DRAW 254

void init_global_tb_data&#40;void&#41;
&#123;
  unsigned short i;
  g_tb_X_versus_Y = &#40;unsigned char *&#41;malloc&#40;6322&#41;;
  g_tb_Y_versus_Z = &#40;unsigned char *&#41;malloc&#40;1298&#41;;
  g_tb_X_versus_Z = &#40;unsigned char *&#41;malloc&#40;5487&#41;;

  for&#40;i = 0; i < 6322; i++)
	g_tb_X_versus_Y&#91;i&#93; = UNKNOWN;

  for&#40;i = 0; i < 1298; i++)
	g_tb_Y_versus_Z&#91;i&#93; = UNKNOWN;

  for&#40;i = 0; i < 5487; i++)
	g_tb_X_versus_Z&#91;i&#93; = UNKNOWN;


&#125;

void solve_some_tablebases&#40;void&#41;
&#123;
  /* some code that will set g_tb_X_versus_Y, g_tb_Y_versus_Z, and g_tb_X_versus_Z */
  /* to some distance to win data, with some of them left UNKNOWN when done        */
  /* I have all of this code, and it works fine.                                   */
&#125;

void set_unknown_tb_to_draws&#40;unsigned char *global_pointer_you_pass_in, unsigned short number_of_positions&#41;
&#123;
  unsigned short i;
  /* I can't seem to have the LOCAL variable here update the GLOBAL data from the outside */
  /* Passing "& g_tb_X_versus_Y" and adding a second star doesn't seem to work either */
  /* This is the code I am having trouble with */

 for&#40;i = 0; i < number_of_positions; i++)
   if&#40;global_pointer_you_pass_in&#91;i&#93; == UNKNOWN&#41;
      global_pointer_you_pass_in&#91;i&#93; = DRAW;
&#125;

void main&#40;void&#41;
&#123;
  init_global_tb_data&#40;);
  solve_some_tablebases&#40;);
  set_unknown_tb_to_draws&#40;g_tb_X_versus_Y, 6322&#41;;
  set_unknown_tb_to_draws&#40;g_tb_Y_versus_Z, 1298&#41;;
  set_unknown_tb_to_draws&#40;g_tb_X_versus_Z, 5487&#41;;
&#125;
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: Silly C Question

Post by Sven »

GothicChessInventor wrote:That only updates the LOCAL variable, not the GLOBAL variable passed in. I know how to do what you have shown.
No, this is wrong, the code proposal of Zach is correct. The local parameter of your function is a pointer variable. When calling that function, you pass the value of your global pointer variable to it, which is the storage address you got returned from malloc. Now your function has a local pointer that points to the same memory as the global pointer. Since the parameter is not declared as "pointer to const", it is possible not only to read from that memory but also to write.
GothicChessInventor wrote:Consider this as a restatement of the problem:

Code: Select all

// ...

void set_unknown_tb_to_draws&#40;unsigned char *global_pointer_you_pass_in, unsigned short number_of_positions&#41;
&#123;
  unsigned short i;
  /* I can't seem to have the LOCAL variable here update the GLOBAL data from the outside */
  /* Passing "& g_tb_X_versus_Y" and adding a second star doesn't seem to work either */
  /* This is the code I am having trouble with */

 for&#40;i = 0; i < number_of_positions; i++)
   if&#40;global_pointer_you_pass_in&#91;i&#93; == UNKNOWN&#41;
      global_pointer_you_pass_in&#91;i&#93; = DRAW;
&#125;

void main&#40;void&#41;
&#123;
  init_global_tb_data&#40;);
  solve_some_tablebases&#40;);
  set_unknown_tb_to_draws&#40;g_tb_X_versus_Y, 6322&#41;;
  set_unknown_tb_to_draws&#40;g_tb_Y_versus_Z, 1298&#41;;
  set_unknown_tb_to_draws&#40;g_tb_X_versus_Z, 5487&#41;;
&#125;
If your program works like this then it should work correctly (I have tested it). If it doesn't then probably you don't show all relevant parts of the real code.

My first proposal: add testing code at the end of main() that loops over your array(s) and exits with an error message if there is any UNKNOWN entry left.

My second proposal: reduce the problem to a smaller one. Put the relevant code (like the one you quoted) into a separate test program, and use only one array instead of three. Throw out step by step anything that seems to be unrelated to your problem, as long as the problem persists.

If the error still appears then post the whole test program code here in a way that others can exactly reproduce your case.

Sven
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: Silly C Question

Post by Sven »

For those interested, proper equivalent C++ code for the given problem could look like this (while avoiding any global variables and also avoiding to use some magic constants more than once in the code):

Code: Select all

#include <assert.h>

class TableBase
&#123;
private&#58;
    unsigned char * m_data;
    unsigned short m_size;

public&#58;
    enum TbValue &#123; UNKNOWN = 255, DRAW = 254 /* and probably more ... */ &#125;;

    unsigned short size&#40;) const;
    TableBase&#40;unsigned short size&#41;;
    ~TableBase&#40;);
    unsigned char & operator&#91;&#93;&#40;unsigned short i&#41;;
    void setUnknownToDraw&#40;);
&#125;;

inline unsigned short TableBase&#58;&#58;size&#40;) const
&#123;
    return m_size;
&#125;

inline TableBase&#58;&#58;TableBase&#40;unsigned short size&#41;
    &#58; m_size&#40;size&#41;,
      m_data&#40;new unsigned char&#91;size&#93;)
&#123;
&#125;

inline TableBase&#58;&#58;~TableBase&#40;)
&#123;
    delete &#91;&#93; m_data;
&#125;

inline unsigned char & TableBase&#58;&#58;operator&#91;&#93;&#40;unsigned short i&#41;
&#123;
    assert&#40;i < size&#40;));
    return m_data&#91;i&#93;;
&#125;

void TableBase&#58;&#58;setUnknownToDraw&#40;)
&#123;
    for &#40;unsigned short i = 0; i < size&#40;); i++) &#123;
        if &#40;m_data&#91;i&#93; == UNKNOWN&#41; &#123;
            m_data&#91;i&#93; = DRAW;
        &#125;
    &#125;
&#125;

int main&#40;)
&#123;
    TableBase tbXversusY&#40;6322&#41;;
    TableBase tbYversusZ&#40;1298&#41;;
    TableBase tbXversusZ&#40;5487&#41;;

    // solve ...

    tbXversusY.setUnknownToDraw&#40;);
    tbYversusZ.setUnknownToDraw&#40;);
    tbXversusZ.setUnknownToDraw&#40;);

    return 0;
&#125;
Sven
User avatar
Bo Persson
Posts: 243
Joined: Sat Mar 11, 2006 8:31 am
Location: Malmö, Sweden
Full name: Bo Persson

Re: Silly C Question

Post by Bo Persson »

Sven Schüle wrote:For those interested, proper equivalent C++ code for the given problem could look like this (while avoiding any global variables and also avoiding to use some magic constants more than once in the code):

Code: Select all

#include <assert.h>

class TableBase
&#123;
private&#58;
    unsigned char * m_data;
    unsigned short m_size;

public&#58;
    enum TbValue &#123; UNKNOWN = 255, DRAW = 254 /* and probably more ... */ &#125;;

    unsigned short size&#40;) const;
    TableBase&#40;unsigned short size&#41;;
    ~TableBase&#40;);
    unsigned char & operator&#91;&#93;&#40;unsigned short i&#41;;
    void setUnknownToDraw&#40;);
&#125;;

inline unsigned short TableBase&#58;&#58;size&#40;) const
&#123;
    return m_size;
&#125;

inline TableBase&#58;&#58;TableBase&#40;unsigned short size&#41;
    &#58; m_size&#40;size&#41;,
      m_data&#40;new unsigned char&#91;size&#93;)
&#123;
&#125;

inline TableBase&#58;&#58;~TableBase&#40;)
&#123;
    delete &#91;&#93; m_data;
&#125;

inline unsigned char & TableBase&#58;&#58;operator&#91;&#93;&#40;unsigned short i&#41;
&#123;
    assert&#40;i < size&#40;));
    return m_data&#91;i&#93;;
&#125;

void TableBase&#58;&#58;setUnknownToDraw&#40;)
&#123;
    for &#40;unsigned short i = 0; i < size&#40;); i++) &#123;
        if &#40;m_data&#91;i&#93; == UNKNOWN&#41; &#123;
            m_data&#91;i&#93; = DRAW;
        &#125;
    &#125;
&#125;

int main&#40;)
&#123;
    TableBase tbXversusY&#40;6322&#41;;
    TableBase tbYversusZ&#40;1298&#41;;
    TableBase tbXversusZ&#40;5487&#41;;

    // solve ...

    tbXversusY.setUnknownToDraw&#40;);
    tbYversusZ.setUnknownToDraw&#40;);
    tbXversusZ.setUnknownToDraw&#40;);

    return 0;
&#125;
Sven
Ok, so I just can't avoid providing this alternate version:

Code: Select all

#include <vector>
#include <algorithm>

// some constants...

typedef std&#58;&#58;vector<unsigned char>   TableBase;

int main&#40;)
&#123;
    TableBase tbXversusY&#40;6322&#41;;
    TableBase tbYversusZ&#40;1298&#41;;
    TableBase tbXversusZ&#40;5487&#41;;

    // solve ...

    std&#58;&#58;replace&#40;tbXversusY.begin&#40;), tbXversusY.end&#40;), UNKNOWN, DRAW&#41;;
    std&#58;&#58;replace&#40;tbYversusZ.begin&#40;), tbYversusZ.end&#40;), UNKNOWN, DRAW&#41;;
    std&#58;&#58;replace&#40;tbXversusZ.begin&#40;), tbXversusZ.end&#40;), UNKNOWN, DRAW&#41;;
&#125;
So the code for a chess program was in the C++ standard library all the time? :-)


Bo Persson
mcostalba
Posts: 2684
Joined: Sat Jun 14, 2008 9:17 pm

Re: Silly C Question

Post by mcostalba »

Bo Persson wrote:
Ok, so I just can't avoid providing this alternate version:
You beat me on time ;-)

I don't know why but there is a diffuse opinion to consider the STL something _outside_ C++, while, actually this is an integral and important part of the standard.

I consider STL one of the main reasons to use C++ instead of something else.
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: Silly C Question

Post by Sven »

Bo Persson wrote:Ok, so I just can't avoid providing this alternate version:

Code: Select all

#include <vector>
#include <algorithm>

// some constants...

typedef std&#58;&#58;vector<unsigned char>   TableBase;

int main&#40;)
&#123;
    TableBase tbXversusY&#40;6322&#41;;
    TableBase tbYversusZ&#40;1298&#41;;
    TableBase tbXversusZ&#40;5487&#41;;

    // solve ...

    std&#58;&#58;replace&#40;tbXversusY.begin&#40;), tbXversusY.end&#40;), UNKNOWN, DRAW&#41;;
    std&#58;&#58;replace&#40;tbYversusZ.begin&#40;), tbYversusZ.end&#40;), UNKNOWN, DRAW&#41;;
    std&#58;&#58;replace&#40;tbXversusZ.begin&#40;), tbXversusZ.end&#40;), UNKNOWN, DRAW&#41;;
&#125;
So the code for a chess program was in the C++ standard library all the time? :-)


Bo Persson
Of course you're right, using STL even makes the self-written part of the program much smaller and much more elegant. My main intention was to show how "plain" C++ can already help to improve over "plain" C in the given case.

Personally I would definitely prefer your short STL-based solution over mine. However, a possible advantage of the non-STL solution is that it "shows the secrets" while yours requires to "believe in the magic" - at least from the viewpoint of those who do not have enough C++ experience yet. So both ways may have their value.

Sven