Skip to content

Arduino - Strings

Arduino - Working with Text: String vs. char arrays

Section titled “Arduino - Working with Text: String vs. char arrays”

Handling text is fundamental in programming. Whether you’re displaying data on an LCD, parsing commands from the Serial Monitor, or interacting with a web API, you’ll need to work with strings. In the Arduino ecosystem, there are two primary ways to handle text, each with significant trade-offs.

  • C-style strings: The traditional, memory-efficient approach using null-terminated arrays of characters (char[]).
  • The String object: A more user-friendly, object-oriented class that simplifies many text manipulation tasks.

Understanding the difference is critical for writing stable and reliable Arduino code, especially on devices with limited memory. This chapter will guide you through both, helping you choose the right tool for the job.

This is the classic way of handling strings inherited from the C language. A string is simply an array of characters that ends with a special ‘null character’ ('\0'), which has an ASCII value of 0. This null character signals the end of the string.

void setup() {
Serial.begin(9600);
// The compiler automatically adds the null terminator '\0'
char myMessage[] = "Hello, Arduino!";
Serial.println(myMessage);
// To find the string length (excluding null terminator)
int len = strlen(myMessage);
Serial.print("Length: ");
Serial.println(len);
// To find the memory size (including null terminator)
int size = sizeof(myMessage);
Serial.print("Size in memory: ");
Serial.println(size); // Will be length + 1
}
void loop() {}

Modifying C-style strings requires care to avoid buffer overflows—writing past the end of the array, which corrupts memory and crashes your program. Always use ‘n’-version functions like strncpy() and strncat(), which limit the number of bytes written.

void setup() {
Serial.begin(9600);
// Create a buffer large enough for future text
char buffer[50] = "Log: ";
// Safely append (concatenate) text
// strncat(destination, source, max_chars_to_copy)
strncat(buffer, "System OK.", sizeof(buffer) - strlen(buffer) - 1);
Serial.println(buffer);
}
void loop() {}

The String object provides a much more intuitive way to work with text. It handles memory allocation for you and lets you use simple operators like + for concatenation.

void setup() {
Serial.begin(9600);
// Create a String object
String greeting = "Hello, ";
// Simple concatenation
greeting += "World!";
Serial.println(greeting);
Serial.print("Length: ");
Serial.println(greeting.length());
// Other useful methods
greeting.replace("World", "Arduino");
Serial.println(greeting);
greeting.toUpperCase();
Serial.println(greeting);
}
void loop() {}

While the String object looks easier, its convenience comes at a hidden cost: dynamic memory allocation.

Analogy: Imagine your Arduino’s RAM is a small parking lot with numbered spaces.

  • char[] is like reserving a block of adjacent spaces (char buffer[50]) for the entire duration of your project. The spots are yours, fixed and predictable.
  • String is like a valet who finds an empty spot for you each time you change the string. If you frequently change your strings (e.g., concatenating in a loop), the valet might have to park your car, then move it to a bigger spot, leaving the old, small spot empty. Over time, the parking lot becomes full of small, unusable empty spots between parked cars. This is called heap fragmentation.

When your Arduino runs out of contiguous memory blocks due to fragmentation, it can’t allocate more memory, and your program will unpredictably crash or behave erratically. This is especially dangerous for projects that need to run reliably for long periods.

Featurechar array (C-style string)String Object
Memory UsageStatic, predictable. You define the size at compile time.Dynamic. Memory is allocated and freed at runtime.
StabilityHigh. No risk of fragmentation. Prone to buffer overflows if not careful.Low in long-running sketches. Can cause heap fragmentation and lead to crashes.
Ease of UseMore complex. Requires functions like strcpy, strcat.Very easy. Uses intuitive operators (+) and methods (.concat(), .replace()).
PerformanceGenerally faster as there’s no overhead from memory management.Slightly slower due to memory allocation and deallocation overhead.
  • For quick tests, simple sketches, or one-off text processing: The String object is perfectly fine and can speed up development.
  • For any project that needs to be reliable, run for a long time, or runs on a device with very little RAM: Strongly prefer char arrays. Learn to use fixed-size buffers and safe functions like snprintf(), strncpy(), and strncat().
  • Avoid String concatenation (+ or +=) inside a loop() at all costs. This is the fastest way to cause heap fragmentation.
  • If you must use the String object, use its reserve() method in setup() to pre-allocate a buffer. This can reduce, but not eliminate, fragmentation issues: myString.reserve(100);