toInt() is not working properly

Hello.
I'm trying to get Arduino to print back values if they are integers with a value between 0 and 255.
The piece of code that checks whether the string from the serial port is an integer is the following:

bool checkStringIsNumerical(String myString)
{
    bool Isnum = false;
    uint16_t Numbers = 0;

    for (uint16_t i = 0; i < myString.length(); i++)
    {
        if (myString[i] >= '0' && myString[i] <= '9')
        {
            Numbers++;
        }
    }

    if (Numbers == myString.length())
    {
        Isnum = true;
    }
    else
    {
        Isnum = false;
    }
    return Isnum;
}

I then call the previous function and check if the value is an integer and between 0 and 255 I print it back to the serial monitor:

if (checkStringIsNumerical(readString))
        {
            if ((readString.toInt() >= 0) && (readString.toInt() <= 255))
            {
              int pol = readString.toInt();
              Serial.println((String) "Input is : " + readString);
              Serial.println((String) "Numeric value is : " + pol);
              Serial.println("-------------------");
            }
        }

The problem: most of the time I get the correct value but sometimes I get a wrong value that is pretty close to the correct value.
Here are some examples(Serial monitor output):
Input is : 101
Numeric value is : 100
-------------------
Input is : 110
Numeric value is : 111
-------------------
Input is : 250
Numeric value is : 255
-------------------
Input is : 210
Numeric value is : 211
-------------------
You can test this in tinkercad here
Thank you

Dunno what is wrong with your code, try this:

bool isStringNumeric(String &str)
{
  uint16_t pos = 0;
  while (pos < str.length())
  {
    if ((str[pos] < '0') || (str[pos] > '9')) return false;
    pos++;
  }
  return true;
}

. . .

if (isStringNumeric(readString))
{
  int val = readString.toInt();
  if ((val >= 0) && (val <= 255))
  {
    Serial.print("Input is : ");
    Serial.println(readString);
    Serial.print("Numeric value is : ");
    Serial.println(val);
    Serial.println("-------------------");
  }
}

Also mind that using the "String" data type on an AVR based Arduino may cause memory corruption which leads to all sorts of havoc.

1 Like

The serial input basics tutorial shows robust ways to read serial data into strings (null terminated character arrays not to be confused with Strings) and parse the data.

1 Like

Have you tried running your code on a real Arduino ?
Here are my results using your code on a Nano

Input is : 101
Numeric value is : 101
-------------------
Input is : 110
Numeric value is : 110
-------------------
Input is : 250
Numeric value is : 250
-------------------
Input is : 210
Numeric value is : 210
-------------------

It seems like the problem is with TinkerCad

2 Likes

TinkerCad doing something different ? That is nuts.

I tried the sketch in the Wokwi simulation, and it works just like the real board.

@newbie_e Could you show a full (short) sketch the next time ?. Now we have to log in at Tinkercad to see the sketch.

Using many String objects with a Arduino Uno might cause the heap to keep growing. We try to avoid the String class with a Arduino Uno.

Could you get used to a indent of 2 spaces instead of 4 in the source code ? Arduino uses default two spaces, and I learned to like it.

A 'myString[i]' is a element in a array of String objects. But you don't have an array of String objects, you have just one object. [EDIT] It is okay as Danois90 writes below

I have made a comparison between Tinkercad and Wokwi: Virtual Online Arduino Simulator - Wokwi Arduino Simulator - #3 by Koepel
I will add the bug that you found, thank you.

1 Like

No, the String class has element access through operators.

2 Likes

Oops, sorry, I will fix my previous post.

This is the minimal test sketch for Tinkercad, I don't know how it is possible, but a cast of a integer to a String object sometimes fails:

// Test this in Tinkercad with Arduino Uno

void setup()
{
  Serial.begin(115200);
  Serial.println( "--------------------");
  
  String Q = "110";
  int value = Q.toInt();
  String R = (String) value;

  Serial.print( "Ojbect Q is of course 110 : ");
  Serial.println( Q);
  Serial.print( "The integer is of course 110 : ");
  Serial.println( value);
  Serial.print( "The cast to String makes it 111 : ");
  Serial.println( R);
}

void loop() {}
1 Like

they know this for a long time...

see https://tinkercad.zendesk.com/hc/en-us/community/posts/115007237807-Circuits-Arduino-String-

1 Like

Thank you all for your replies.
I did as @Danois90 suggested to avoid converting the integer to string and just used a separate Serial.println to print the value.
Thanks again for your help.