Need some C++ string help please

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

Mike Sherwin
Posts: 866
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Need some C++ string help please

Post by Mike Sherwin »

Code: Select all

char data[256];

s32 GetData(char* data) {
  s32 cnt = 0, i; char c;
  for (i = 0; i < 256; i++) {
    scanf_s("%c", &c, 1); // keyboard input sd 7
    if (c != ' ' && c != '\n') {
      data[i] = c;
      cnt++;
    }
    else break;
  }
  data[i] = '\n';
  return cnt;
}

cnt = GetData(&data[0]);

// data[0] == 's' //  yes
// data[1] == 'd' //  yes
// data[2] == '\n' // yes

if (!strcmp(data, "sd\n")) {
    GetData(&data[0]); // if body not executed
    sd = std::stoi(data, nullptr);
}
Mike Sherwin
Posts: 866
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: Need some C++ string help please

Post by Mike Sherwin »

Well I found this online:

Code: Select all

string temp = fullname;

string firstName = temp.substr(0, temp.find(" "));

temp = temp.substr(temp.find(" ")+1);
string middleName = temp.substr(0, temp.find(" "));

string lastName = temp.substr(temp.find(" ")+1);
So I'm going to try this approach.
Mike Sherwin
Posts: 866
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: Need some C++ string help please

Post by Mike Sherwin »

Found getline which does what I wanted to do. So I think I got it.
User avatar
lucasart
Posts: 3232
Joined: Mon May 31, 2010 1:29 pm
Full name: lucasart

Re: Need some C++ string help please

Post by lucasart »

Mike Sherwin wrote: Tue Oct 06, 2020 4:35 am Found getline which does what I wanted to do. So I think I got it.
Yes, the best code is the code you don't write. Use std::getline in C++, or getline in C (POSIX only though).

If you want to reinvent getline, here are the important ingredients:
* buffer can't be a fixed size array, you must realloc (not one byte at a time, obviously, but using an allocation strategy, like doubling each time you exceed bounds).
* scanf is an exceptionally bad choice for reading a character. Parsing overhead, of course. But also, locking overhead. You need to lock/unlock only once per line, and use getc_unlocked() in the loop by character.

In C, fgets() is fine, but uses a fixed array as output, with the usual consequences…
Theory and practice sometimes clash. And when that happens, theory loses. Every single time.
Mike Sherwin
Posts: 866
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: Need some C++ string help please

Post by Mike Sherwin »

lucasart wrote: Tue Oct 06, 2020 6:37 am
Mike Sherwin wrote: Tue Oct 06, 2020 4:35 am Found getline which does what I wanted to do. So I think I got it.
Yes, the best code is the code you don't write. Use std::getline in C++, or getline in C (POSIX only though).

If you want to reinvent getline, here are the important ingredients:
* buffer can't be a fixed size array, you must realloc (not one byte at a time, obviously, but using an allocation strategy, like doubling each time you exceed bounds).
* scanf is an exceptionally bad choice for reading a character. Parsing overhead, of course. But also, locking overhead. You need to lock/unlock only once per line, and use getc_unlocked() in the loop by character.
THANKS! :D
Mike Sherwin
Posts: 866
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: Need some C++ string help please

Post by Mike Sherwin »

I don't know if I had an epiphany or just another one of my many duh moments. So, when I was contemplating the situation I was staring at a cout line. Then it hit me, if there is a cout then there must be a cin. Problem solved! I spent hours and hours because I forgot that cin existed. Dumb Donkey strikes again. :evil: I'm so tired by not being able to remember. :cry:
Mike Sherwin
Posts: 866
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: Need some C++ string help please

Post by Mike Sherwin »

Mike Sherwin wrote: Tue Oct 06, 2020 7:05 am I don't know if I had an epiphany or just another one of my many duh moments. So, when I was contemplating the situation I was staring at a cout line. Then it hit me, if there is a cout then there must be a cin. Problem solved! I spent hours and hours because I forgot that cin existed. Dumb Donkey strikes again. :evil: I'm so tired by not being able to remember. :cry:
Turns out that I had neither an epiphany or a duh moment. I looked at dozens and dozens of replies to this simple question, 'how do I parse an unknown number of inputs in C++'. And no one had the answer. All the replies required hitting enter more than once. I was about to quit looking. But, I decided to change the google search phrase and look again. Once again there were no good answers. I was again going to call it quits but decided to click on one more search result. I looked through the answers and found one that was different that looked like it would work. And it did. And it was so simple even I could understand it. That demonstrates what is so wrong with C++. When all those pretend experts that answer peoples questions can't get it right then how does a hobbyist or amature or someone like me have a snowball's chance in hell to figure out how to do something? I wish that I would have stuck with C code. Here is a simple and correct solution.

Code: Select all

void GetCmd(Thread* t) {
  s32 match, i, j = 0, fs, ts;
  u64 n, cnt, epbit;
  string cmd, data, movstr;
  char mvstr[20];
  
  match = false;
  epbit = epbb[1];

  PrintBoard(t);

  cout << "Enter Command: ";

  getline(cin, cmd);
  istringstream iss(cmd);
  iss >> data;
  
  cnt = data.length();

  if (cnt == 4 || cnt == 5) {
    if (data[0] >= 'a' && data[0] <= 'h' &&
        data[1] >= '1' && data[1] <= '8' &&
        data[2] >= 'a' && data[2] <= 'h' &&
        data[3] >= '1' && data[3] <= '8') {
      epbb[0] = epbit;
      n = GenMoves(t, &move[0]);
      for (i = OO; i < n; i++) {
        if (cnt == 5) {
          if (data[5] == 'b') j = 0;
          if (data[5] == 'r') j = 1;
          if (data[5] == 'n') j = 2;
          if (data[5] == 'q') j = 3;
          if (promoType[wtm][j] != move[i].type) continue;
        }
        fs = move[i].fs;
        ts = move[i].ts;
        sprintf_s(mvstr, 20, "%c%d%c%d\n", (fs & 7) + 'a', (fs >> 3) + 1, (ts & 7) + 'a', (ts >> 3) + 1);
        string movstr = mvstr;
        if (!data.compare(movstr)) {
          gameMoves[gamePly].fs = fs;
          gameMoves[gamePly].ts = ts;
          gameMoves[gamePly].type = move[i].type;
          MakeMove(t, &gameMoves[gamePly]);
          epbb[0] = epbit;
          gamePly++;
          ply--;
          return;
        }
      }
      return;
    }
  }

  if (!data.compare("go")) {
    bricabrac = BRICABRAC;
    return;
  }

  if (gamePly && (!data.compare("u") || !data.compare("undo"))) {
    gamePly--;
    ply++;
    TakeBack(t, &gameMoves[gamePly]);
    return;
  }

  if (!data.compare("sd")) {
    iss >> data;
    sd = stoi(data, nullptr);
  }

}
And this is what only that one poster offered.
istringstream iss(cmd); // sets cmd to be accessed by istringstream
iss >> data; // gets the first parameter

then.

if (!data.compare("sd")) {
iss >> data; // gets the next parameter
sd = stoi(data, nullptr);
}
Mike Sherwin
Posts: 866
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: Need some C++ string help please

Post by Mike Sherwin »

Given my memory disability all anyone had to do was reply.

"strtok"

And they would have saved me a days work. :(
User avatar
lucasart
Posts: 3232
Joined: Mon May 31, 2010 1:29 pm
Full name: lucasart

Re: Need some C++ string help please

Post by lucasart »

Mike Sherwin wrote: Tue Oct 06, 2020 8:42 pm Given my memory disability all anyone had to do was reply.

"strtok"

And they would have saved me a days work. :(
There were some bad choices made in the design of the C standard library, and strtok() is probably the worst among them. If you're a casual programmer who doesn't care too much how it works, and just wants things to work, use C++ stringstream.

Here are the 3 cardinal sins of strtok:
  • not re-entrant. yes, the current position in the string is stored as a static variable in the strtok function. seriously... that makes it unusable in multi-threaded context, but not only. it also makes unusable for single threaded programming, because of nested function calls (say f() parses a string, and in that parsing loop calls g(), everything works, yeah! then some idiot changes g() and does some strtok work there, or introduces a call to h(), which does some strtok()... oops! been there, done that, got the t-shirt).
  • totally stupid API. why the hell do I have to pass NULL to continue? why can't the API be consistent whether I parse the first token or sub-sequent tokens?
  • destroys the input string. as it parses, it litters the original string with '\0'. so the original string is basically destroyed and can't be used anymore, at least not with C standard library functions (which stop at the first '\0'). it should take the token output as parameter. of course, that means relying on a fixed size output (with the usual buffer overrun issues). but that's C for you. don't like it, write your own dynamic string library.
strtok_r() fixes the first issue, but doesn't adress the other 2. it's at least usable, just annoying.

If you insist on using a pure C solution, you really should stay away from strtok, and write your own. As you can see, it's not that difficult:
https://github.com/lucasart/c-chess-cli ... str.c#L192

And for getline:
https://github.com/lucasart/c-chess-cli ... str.c#L263
Theory and practice sometimes clash. And when that happens, theory loses. Every single time.
Mike Sherwin
Posts: 866
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: Need some C++ string help please

Post by Mike Sherwin »

lucasart wrote: Wed Oct 07, 2020 1:55 am
Mike Sherwin wrote: Tue Oct 06, 2020 8:42 pm Given my memory disability all anyone had to do was reply.

"strtok"

And they would have saved me a days work. :(
There were some bad choices made in the design of the C standard library, and strtok() is probably the worst among them. If you're a casual programmer who doesn't care too much how it works, and just wants things to work, use C++ stringstream.

Here are the 3 cardinal sins of strtok:
  • not re-entrant. yes, the current position in the string is stored as a static variable in the strtok function. seriously... that makes it unusable in multi-threaded context, but not only. it also makes unusable for single threaded programming, because of nested function calls (say f() parses a string, and in that parsing loop calls g(), everything works, yeah! then some idiot changes g() and does some strtok work there, or introduces a call to h(), which does some strtok()... oops! been there, done that, got the t-shirt).
  • totally stupid API. why the hell do I have to pass NULL to continue? why can't the API be consistent whether I parse the first token or sub-sequent tokens?
  • destroys the input string. as it parses, it litters the original string with '\0'. so the original string is basically destroyed and can't be used anymore, at least not with C standard library functions (which stop at the first '\0'). it should take the token output as parameter. of course, that means relying on a fixed size output (with the usual buffer overrun issues). but that's C for you. don't like it, write your own dynamic string library.
strtok_r() fixes the first issue, but doesn't adress the other 2. it's at least usable, just annoying.

If you insist on using a pure C solution, you really should stay away from strtok, and write your own. As you can see, it's not that difficult:
https://github.com/lucasart/c-chess-cli ... str.c#L192

And for getline:
https://github.com/lucasart/c-chess-cli ... str.c#L263
There is always something behind unopened doors! Thanks for the info on strtok. :D