Edit: I wrote this small test program to show the behaviour of the
heap when you use string concatenation this way:
extern uintptr_t __brkval;
String f() {
String s("");
const char * p = s.c_str();
Serial.print(F(" f(): string buffer @ 0x"));
Serial.println((uintptr_t) p, 16);
for (int i = 0; i < random(8) + 1; i++)
s += random(2) ? "a": "bc";
if (p != s.c_str())
Serial.println(F("Warning: memory fragmentation."));
Serial.print(F(" top of heap at 0x"));
Serial.println(__brkval, 16);
return s;
}
void setup() {
Serial.begin(9600);
Serial.print(F("*** heap starts at 0x"));
Serial.println((uintptr_t) __malloc_heap_start, 16);
}
void loop() {
Serial.print(F("loop(): top of heap at 0x"));
Serial.println(__brkval, 16);
String s = f();
Serial.print(F(" f() returned "));
Serial.println(s);
delay(2000);
}
The output of the program is:
*** heap starts at 0x1D7
loop(): top of heap at 0x0
f(): string buffer @ 0x1D9
top of heap at 0x1DF
f() returned abcbc
loop(): top of heap at 0x1D7
f(): string buffer @ 0x1D9
top of heap at 0x1DF
f() returned abcbc
loop(): top of heap at 0x1D7
f(): string buffer @ 0x1D9
top of heap at 0x1DC
f() returned aa
loop(): top of heap at 0x1D7
f(): string buffer @ 0x1D9
top of heap at 0x1E2
f() returned aabcabca
[...]
The very first “top of heap at” is bogus because at this point the
malloc library has not been initialized. Besides that, you can see here
that:
- the heap is always empty (top = bottom) at the beginning of
loop()
- the string is always allocated at the same place
- the heap size inside
f() varies depending on the string's length.
Keep in mind that this works so nicely only because there is nothing
else doing dynamic allocation in this small program. This usage pattern
is safe, but once you start doing dynamic allocation in different parts
of the program, it becomes difficult to ensure that the
allocation/deallocation pattern is still safe vs. memory fragmentation.