0

Im using this atoi to remove all letters from the string. But my string uses special characters as seen below, because of this my atoi exits with an error. What should I do to solve this?

#include <iostream>
#include <string>
using namespace std;
 
int main() {
    std::string playerPickS = "Klöver 12"; // string with special characters
 
    size_t i = 0;
    for (; i < playerPickS.length(); i++) { if (isdigit(playerPickS[i])) break; }
 

    playerPickS = playerPickS.substr(i, playerPickS.length() - i); // convert the remaining text to an integer
 
    cout << atoi(playerPickS.c_str());
 
}

This is what I believe is the error. I only get this when using those special characters, thats why I think thats my problem.

assert failure

  • 1
    When you say that your "atoi exits with an error", what do you mean by that? What "error"? Please [edit] your question to give us more details. Also please take some time to read [the help pages](http://stackoverflow.com/help), take the SO [tour], read [ask], as well as [this question checklist](https://codeblog.jonskeet.uk/2012/11/24/stack-overflow-question-checklist/). – Some programmer dude Dec 13 '21 at 13:06
  • Is there any way to remove special characters from a string? – Alexander Ström Dec 13 '21 at 13:06
  • It works here: https://ideone.com/lB6yWG – VLL Dec 13 '21 at 13:07
  • 1
    @AlexanderStröm That's a completely separate question. Your code snippet is not complete. This is a trivial case where you should be able to easily produce a [mcve]. – J... Dec 13 '21 at 13:07
  • If you know there's a space between the card color name and its value, why don't you look for that specifically? Or use [`std::find_if`](https://en.cppreference.com/w/cpp/algorithm/find_if) to find the first digit? – Some programmer dude Dec 13 '21 at 13:08
  • 1
    What encoding does your compiler use to create the string literal, or what are the values of each byte in the string? Did you call `setlocale`? – aschepler Dec 13 '21 at 13:09
  • `isdigit` has a locale-aware overload `template bool isdigit( charT ch, std::locale const& loc );`. `atoi` comes from C, which has no overloads – MSalters Dec 13 '21 at 13:16
  • This assertion is triggered since encoding of string is different then encoding expected by `atoi`, as a result `isdigit` function triggers that assertion. – Marek R Dec 13 '21 at 13:18
  • Why do you blame `atoi`? That looks like an `isdigit` assert. – MSalters Dec 13 '21 at 13:18
  • _Always_ convert to `unsigned char` before using `std::isdigit` or any of the `cctype` functions. The `ö` may very well have a negative `char` in it and in that case `isdigit` has _undefined behavior_. – Ted Lyngmo Dec 13 '21 at 13:22
  • 1
    [Why shouldn't I use atoi()? (duplicate)](https://stackoverflow.com/q/17710018/995714). Use `strtol` instead – phuclv Dec 13 '21 at 13:23

2 Answers2

3

char can be signed or unsigned, but isidigt without a locale overload expects a positive number (or EOF==-1). In your encoding 'ö' has a negative value. You can cast it to unsigned char first: is_digit(static_cast<unsigned char>(playerPickS[i])) or use the locale-aware variant.

MSalters
  • 173,980
  • 10
  • 155
  • 350
1

atoi stops scanning when it finds something that's not a digit (roughly speaking). So, to get it to do what you want, you have to feed it something that at least starts with the string you want to convert.

From the documentation:

[atoi] Discards any whitespace characters until the first non-whitespace character is found, then takes as many characters as possible to form a valid integer number representation and converts them to an integer value. The valid integer value consists of the following parts:

  • (optional) plus or minus sign
  • numeric digits

So, now you know how atoi works, you can pre-process your string appropriately before passing it in. Good luck!


Edit: If your call to isdigit is failing to yield the desired result, the clue lies here:

The behavior is undefined if the value of ch is not representable as unsigned char and is not equal to EOF.

So you need to check for that yourself before you call it. Casting playerPickS[i] to an unsigned int will probably work.

Paul Sanders
  • 24,133
  • 4
  • 26
  • 48