Arduino strings: text you can join, compare and take apart
Beginner
Or see every lesson.
- 455parts on the bench
- 43boards running now
- 1.00xreal time, on every board
Arduino has two kinds of text. A String, with a capital S, is an object that grows as you need it: join two with +, compare them with ==, and turn "42" into the number 42 with toInt(). A char array, such as char name[] = "Mokxi";, is the older C kind: a row of characters ending in a zero byte. Most beginners want String; most libraries hand you char arrays.
The circuit above is a 16 by 2 LCD on an Uno. Press Run. The top line says "Mokxi LCD1602" and the bottom line scrolls "Hello from the Uno!" across, one letter at a time. The message is a char array, and the sketch prints it from a different starting letter every 300 ms.
Below is how to build, join, convert, compare and split Strings, the four mistakes that print the wrong thing or stop the build, and how a char array is laid out, each run on an Uno with what it printed.
The scrolling message is an array of letters
Here is the sketch running above. MESSAGE holds 22 letters and spaces, and the compiler adds a zero byte on the end, so sizeof(MESSAGE) - 1 is the number of letters. Each time around, the loop prints 16 of them starting at start, and % length wraps back to the beginning, so the end of the message runs into its start.
Change the text between the quotes and press Run, and the LCD scrolls your words instead. Leave the three spaces on the end; they are the gap before it comes around again.
const char MESSAGE[] = "Hello from the Uno! ";
int start = 0;
void setup() {
lcd.begin(16, 2);
lcd.print("Mokxi LCD1602");
Serial.begin(9600);
Serial.println("Mokxi Uno: LCD1602 on pins 4, 6 and 10 to 13");
}
void loop() {
int length = sizeof(MESSAGE) - 1;
lcd.setCursor(0, 1);
for (int i = 0; i < 16; i++) lcd.print(MESSAGE[(start + i) % length]);
start = (start + 1) % length;
delay(300);
}Make a String and join it
A String is made from text in double quotes, and + joins it to more text, another String or a number wrapped in String(). The sketch below printed "Hello, Mokxi!" and its length(), 13. += adds to the end of a String you already have: "Count: 5" became "Count: 5 lamps".
String() also writes numbers the way you ask. String(3.14159, 3) printed 3.142, with three places. String(255, HEX) printed ff and String(5, BIN) printed 101, which is handy for showing a sensor’s register or the bits of a byte.
void setup() {
Serial.begin(9600);
String name = "Mokxi";
String greeting = "Hello, " + name + "!";
Serial.println(greeting);
Serial.println(greeting.length());
int count = 5;
String line = "Count: " + String(count);
Serial.println(line);
line += " lamps";
Serial.println(line);
Serial.println(String(3.14159, 3));
Serial.println(String(255, HEX));
Serial.println(String(5, BIN));
}
void loop() {
}The + that does not join
The + only joins when one side is a String. Text in quotes on its own is a char array, and adding a number to that moves along it instead. String line = "Count: " + count; with count at 5 skipped the first five letters and printed ": ". Clang warned: adding 'int' to a string does not append to the string. The fix is the one above: "Count: " + String(count).
Two pieces of quoted text cannot be added at all. String both = "Hello" + "World"; stopped the build: clang says invalid operands to binary expression ('const char[6]' and 'const char[6]'), and the Arduino IDE’s GCC says invalid operands of types 'const char [6]' and 'const char [6]' to binary 'operator+'. Make the first one a String, String("Hello") + "World", and the rest follow.
Quotes matter too. Single quotes are for one character, 'A'. String s = 'hi'; stopped the build with no viable conversion from 'int' to 'String', after a warning about a multi-character character constant. Text always goes in double quotes.
String to int, and back
toInt() reads the number at the start of a String. String a = "42"; then a.toInt() + 1 printed 43. It stops at the first character that is not part of a number, so "12abc" gave 12, it skips spaces in front, so " 7" gave 7, and it gives 0 when there is no number at all: "abc" gave 0. toFloat() does the same with decimals, and "3.75" doubled printed 7.50.
toInt() hands back a long, so it can read big numbers, but the variable you keep it in has to be big enough too. "99999" printed 99999 straight from toInt(), and -31073 once it was stored in an int, which on an Uno stops at 32767. Store it in a long. Going the other way, a number becomes a String with String(42).
void setup() {
Serial.begin(9600);
String a = "42";
Serial.println(a.toInt() + 1);
Serial.println(String("12abc").toInt());
Serial.println(String("abc").toInt());
Serial.println(String(" 7").toInt());
String t = "3.75";
float f = t.toFloat();
Serial.println(f * 2);
Serial.println(String("99999").toInt());
int n = String("99999").toInt();
Serial.println(n);
}
void loop() {
}Compare Strings, and char arrays
== compares two Strings letter by letter, and capitals count: "ON" == "on" printed 0, false. equalsIgnoreCase() printed 1, or call toLowerCase() on the String first and then compare. compareTo() puts words in alphabetical order: "apple" compared with "banana" is less than zero.
With char arrays, == does not compare the letters at all; it asks whether they are stored in the same place. char word[] = "on"; then if (word == "on") printed "different". Clang warned: result of comparison against a string literal is unspecified (use an explicit string comparison function instead). That function is strcmp(), which returns 0 when the two match: strcmp(word, "on") == 0 printed "strcmp: same".
void setup() {
Serial.begin(9600);
String cmd = "ON";
Serial.println(cmd == "on");
Serial.println(cmd.equalsIgnoreCase("on"));
cmd.toLowerCase();
Serial.println(cmd == "on");
char word[] = "on";
if (word == "on") Serial.println("same");
else Serial.println("different");
if (strcmp(word, "on") == 0) Serial.println("strcmp: same");
}
void loop() {
}Split a line: indexOf() and substring()
A sensor or another board often sends several values on one line with commas between, such as "21.5,48,1013". indexOf(',') finds where the first comma is, 4 here, and indexOf(',', first + 1) finds the next one after it. substring(from, to) cuts out the part in between, from from up to but not including to, and toFloat() or toInt() turns each part into a number. The sketch below printed 21.50, 48 and 1013.
indexOf() returns -1 when it finds nothing, so check for that before you cut. A few more that come up: charAt(0) or data[0] is one character, replace("l", "L") turned "Hello" into "HeLLo", toUpperCase() made it "HELLO", and trim() takes spaces and line endings off both ends, which the serial read page shows is often what a comparison needs.
void setup() {
Serial.begin(9600);
String data = "21.5,48,1013";
int first = data.indexOf(',');
int second = data.indexOf(',', first + 1);
float temp = data.substring(0, first).toFloat();
int humidity = data.substring(first + 1, second).toInt();
long pressure = data.substring(second + 1).toInt();
Serial.println(temp);
Serial.println(humidity);
Serial.println(pressure);
}
void loop() {
}char arrays, and the zero on the end
char name[] = "Mokxi"; holds five letters and one more byte, a zero, that marks the end. sizeof(name) printed 6 and strlen(name), which counts up to the zero, printed 5. Each letter is an entry like any array: name[0] printed M, and after name[0] = 'm'; the name printed "mokxi".
A String and a char array convert both ways. String s = name; makes a String from the array, and s.c_str() hands a String to a function that wants a char array, as many library functions do.
A String keeps its letters in memory it asks for while the sketch runs, and gives back when it is done. On an Uno, with 2048 bytes of RAM for everything, a sketch that builds long Strings over and over in loop() can run short of memory after hours of running. For short messages that is nothing to worry about. For a sketch that runs for days, keep text in char arrays or call reserve() once in setup(); the low memory page has the rest.
Questions
What is the difference between String and string in Arduino?
String with a capital S is the Arduino object you can join with +, compare with == and convert with toInt(). A lower case string usually means a char array, such as char name[] = "Mokxi";, a row of characters ending in a zero byte.
How do I convert a String to an int in Arduino?
Call toInt() on it: String("42").toInt() is 42. It returns a long and gives 0 when the text does not start with a number. Use toFloat() for decimals.
How do I join a String and a number?
Wrap the number in String(): "Count: " + String(count). Without it, "Count: " + count moves along the text by count letters instead of joining, and prints part of it.
How do I compare two strings in Arduino?
Two Strings compare with ==, and capitals count; use equalsIgnoreCase() to ignore them. For char arrays use strcmp(a, b) == 0, because == on char arrays compares where they are stored, not what they say.
How do I split a String by commas?
Find each comma with indexOf(','), cut out the pieces with substring(), and convert them with toInt() or toFloat(). The example on this page reads three values from "21.5,48,1013".
How do I get the length of a String in Arduino?
`s.length()` counts the characters: "Hello" with " world" added on printed 11. For a char array, `strlen(c)` gives 11 too, while `sizeof(c)` gives 12, because it also counts the zero byte that ends the text.
Keep going
Where the facts on this page come from
Build this for real
Open the editor, change a value and watch the number move with it. Nothing to install, and no account needed.