substring to int?

I'm reading a series of char[20] and converting that into a string "Data" so that I can use the #include <string.h> substring . as you can see in the code i'm always going to be parsing 3 digit (positive) numbers to store then in the EEPROM. I've attached the snipped of code where my problem is with and example string. My problem seams to be when i use the atoi function. Any help?

#include <String.h>
#include <EEPROM.h>

char incomingSerialDataString[20] = "IP 192.168.001.011";
  String Data = incomingSerialDataString;
  
  if(Data.startsWith("IP"))
  {
   String FirstIP =  Data.substring(3,6);
   String SecondIP = Data.substring(7,10);
   String ThirdIP = Data.substring(11,14);
   String ForthIP = Data.substring(15,18);
   
   Serial.println(FirstIP);
   Serial.println(SecondIP);
   Serial.println(ThirdIP);
   Serial.println(ForthIP);
   
   int First = atoi(FirstIP);
   int Second = atoi(SecondIP);
   int Third = atoi(ThirdIP);
   int Forth = atoi(ForthIP);
   
   EEPROM.write(0, First);
   EEPROM.write(1, Second);
   EEPROM.write(2, Third);
   EEPROM.write(3, Forth);
  }

You can't call atoi() on a String.

You need to pull out the characters first. See docs at http://arduino.cc/en/Reference/StringObject for various ways to do that.

Alternatively, you can call int() on these Strings to get integers.

johnmchilton:
Alternatively, you can call int() on these Strings to get integers.

How so?

I could be wrong, but the reference page at int() - Arduino Reference says you can pass it any type...

I'm not near an Arduino right now, and I can't find the source in the Arduino package, but I would have to assume since this compiles in the first place that the library handles it intelligently.

from version 22 the string class contains a toInt() member function. See - C:\Program Files (x86)\arduino-0022\hardware\arduino\cores\arduino\Wstring.h - (Win 7)

So you could place the substring in a separate string XXX and call x = XXX.toInt();

It just does an atol on its internal buffer

long String::toInt() {
  return atol(_buffer);
}

Alternatively, get rid of the String object altogether. Everything you are doing with String::substring can be done with strtok() instead. The output from the strtok() function is a NULL-terminated array of characters, which is exactly what atoi() wants.

Getting rid of the String object will greatly reduce the size of your code. In addition, the strtok() function does not care how long the substring is. You can then parse the more normal "IP 192.168.1.11".

Somewhat klunky, but another way of changing a string to an integer.

    Serial.println(readstring);  //so you can see the captured string 
    char carray[readstring.length() + 1]; //determine size of the array
    readstring.toCharArray(carray, sizeof(carray)); //put readstring into an array
    int n = atoi(carray); //convert the array into an Integer

PaulS do you have any example code of useing strtok() to do it?

Thanks in advance.

Something like this should work

char incomingSerialDataString[20] = "IP 192.168.1.11";
char *token;
byte addr[4];
byte index;

void setup()
{
   token = strtok(incomingSerialDataString, " "); // Couldn't you have used a longer name?
   // token will be "IP", and the space will be skipped.

   index = 0;
   token = strtok(NULL, ","); // token will be "192"
   while(token)
   {
      if(index < 4)
         addr[index++] = atoi(token); // addr[0] will be 192...

      token = strtok(NULL, ","); // token will be "168", "1", "11", and NULL
   }
}

void loop()
{
}

Thanks PaulS! I replaced the "," with "." and your example code helped a LOT. It didn't save much room on the Arduino but it was a lot clearer looking then the alternatives out there and saved me an #include.

Thanks everyone for the input.

PS I like using very descriptive variable names so when i look at the code a year or 2 from now it will make sense faster and copy and paste are a great thing.

I replaced the "," with "."

Oops...

PS I like using very descriptive variable names

I do to, but there are reasonable names and really long names... :slight_smile:

I know this is a very old post but I found the code from PaulS to be very helpful.
I have however trouble understanding how number 20 is defined in:

char incomingSerialDataString[20] = "IP 192.168.1.11";

It works perfect in the example, I just don't understand where the 20 comes from...
I tried adapting the code to my needs:

char recieveDate[20] = "setDate 2017.12.31.6.14.51.11";
// Year.Month.Day of month.Day of week (1-7).Hour.Minute.Second

Since I have 7 fields (tokens?) (0-6) I thought I would change
byte addr[7];
and
if(index < 7)

I increased the [20] to [30] and the output I receive is:
225
12
31
6
14
51
11

I am sure this is very basic for most people here but I have a hard time finding the information on google, probably because I am searching with the wrong questions :slight_smile:

I don't understand why it would output 255 instead of 2017

Could someone shine some light on what this number [20] means and how to calculate the correct number?

Thanks in advance! :slight_smile:

char recieveDate[30] = "setDate 2017.12.31.6.14.51.11"; // Year.Month.Day of month.Day of week (1-7).Hour.Minute.Second
//  char myStr[] = "setDate 2017.12.31.6.14.51.11"; // Year.Month.Day of month.Day of week (1-7).Hour.Minute.Second
char *token;
byte addr[7];
byte index;

void setup()
{
  Serial.begin(9600);  //  serial  communication to  check the data  on  serial  monitor 
  token = strtok(recieveDate, " "); // Couldn't you have used a longer name?
  // token will be "IP", and the space will be skipped.

  index = 0;
  token = strtok(NULL, "."); // token will be "192"
  while(token)
  {
     if(index < 7)
        addr[index++] = atoi(token); // Assign addr[x] to the tokens (x = 0-6)

     token = strtok(NULL, "."); 
  }
}

void loop()
{
  Serial.println(addr[0]);
  Serial.println(addr[1]);
  Serial.println(addr[2]);
  Serial.println(addr[3]);
  Serial.println(addr[4]);
  Serial.println(addr[5]);
  Serial.println(addr[6]);
  Serial.println(" ");
//  Serial.println(sizeof(myStr));
  Serial.println(" ");
  delay(10000);
}

I solved my problem for many years to come so it's no longer an issue for me :slight_smile:
And I found out that I will have to read up on allocated memory.

char recieveDate[] = "setDate 17.12.31.6.14.51.11"; // Year.Month.Day of month.Day of week (1-7).Hour.Minute.Second
char* strDays[]={"SUNDAY", "MONDAY", "TUESDAY","WEDNESDAY", "THURSDAY","FRIDAY", "SATURDAY"};
char *token;
byte addr[7];
byte index;

void setup()
{
  Serial.begin(9600);  //  serial  communication to  check the data  on  serial  monitor 
  token = strtok(recieveDate, " "); // Couldn't you have used a longer name?
  // token will be "IP", and the space will be skipped.

  index = 0;
  token = strtok(NULL, "."); // token will be "192"
  while(token)
  {
     if(index < 7)
        addr[index++] = atoi(token); // Assign addr[x] to the tokens (x = 0-6)

     token = strtok(NULL, "."); 
  }
}

void loop()
{
  Serial.println(addr[0]+2000);
  Serial.println(addr[1]);
  Serial.println(addr[2]);
  Serial.println(strDays[addr[3]]);
  Serial.println(addr[4]);
  Serial.println(addr[5]);
  Serial.println(addr[6]);
  Serial.println(" ");
  Serial.println(" ");
  delay(15000);
}