Is String function family inherently dangerous?

One additional disadvantage of String is that if you seek help here with an occaisional crash or other bizarre behaviour and you have used them, the likely advice will be no more than “Get rid of the Strings, it’s probably them” because debugging such a sketch is a lot more work than folks really want to do.

In this post, I posted some modifications to the String class that can be used to demonstrate why String can be bad.

Even if you have a processor with a lot of memory, why would you want to waste it? Saying that the String class is "easier to use" than the C string functions (str* and mem*) simply tells me you haven't spent much time using C strings.

Is the String class bad on all processors? I don't know. If you're in that situation, too, write a short program using Strings and they rewrite it using char arrays and look at the difference in resource use (if any). It's choice you need to make, not us, and the answer will likely vary from one processor to the next.

sterretje:
In this post, I posted some modifications to the String class that can be used to demonstrate why String can be bad.

That’s a pretty gross simplification, unless the malloc/free logic has gotten massively hosed since the last time I looked at it. When doing a malloc, the first block large enough to satisfy the request is used. So, a small request will, often as not, likely re-use an existing small free block. Also, fragments ARE re-combined with adjacent free blocks into single larger blocks whenever possible. So, those little fragments WILL be re-combined, creating fewer, larger blocks.
Whether fragmentation ends up breaking up memory into a slew of unusable small, non-contiguous blocks is a function of the sequence in which blocks are allocated and freed. If, for example, you allocate a bunch of blocks, then free all of them, you’ll be right back where you started. If you create, then discard, String objects as local variables in a function, you’ll be right back where you started.
So, in your example, those freed blocks do no disappear, they be re-used, if possible. The fact that reducing a String objects buffer does not move the buffer back to its previous location is not necessarily good nor bad - it could be either, or neither, depending on what else has happened to the free chain. You have NO way of knowing for any particular instance.
Bottom line - many uses of String will work just fine. Don’t get carried away creating huge numbers of persistent, or very large Strings. ALWAYS delete them as soon as possible. Get sloppy, and you’ll have trouble for sure. But if you can design so your Strings are short-lived, and are ALWAYS properly deleted, you may never have a problem.
Regards,
Ray L.

So on something unimportant, that doesn’t need to run for days, sure, use String if you want to

That is an important snip for me out of this thread. The rest of the discussion is really interesting but mostly a few feet over my head; I feel kind of honoured actually, to have started such a high-level discourse by asking such a dumb-bunny question :slight_smile:

But this is nuts&bolts, rule of thumb stuff that I can understand. The sketch I’m working on is for a USB game controller that gets power cycled every time it gets used. So…

  • I’ll be using less than 50 % of available memory on my Due and
  • I don’t need the sketch to run for more than about 2 or 3 hours at a time, and
  • my objective is not (immediately) to Become a Better C Programmer but To Get My Hardware To Work, Soon.

So I think I’ll stick with String for now.

But when I attack my next project, a well water-level monitoring system that does have to run 24x7x365, then I will grit my teeth and learn to manage char arrays and pointers properly because that system will be based on a cheaper smaller arduino, maybe one of those WeMOS doohickies with built in WiFi, and it needs to be installed in a remote location and stay rock solid without intervention. For that application it sounds like String is not my friend.

And for that essential insight (where not to use String) I’m really grateful to everyone. I think the Arduino Forum is just about the poster child for how technical fora ought to be. It’s a great community. Molte grazie :slight_smile:

I'll just add that if you decide to use String, be sure to check the results of all memory allocations. That way you'll know if your code is failing because of memory fragmentation rather than some other issue.

My take on it is:
Yes, String can be used safely - but by the time you are familiar enough with how things work under the hood to recognize what cases are safe, you'd be comfortable using char arrays, which typically uses less flash (since it doesn't have to pull in the malloc-related functions), making String less attractive. The official documentation certainly gives no hints as to how to use it safely.

dnwheeler:
I’ll just add that if you decide to use String, be sure to check the results of all memory allocations.

They’ll be mostly encapsulated in the class.

  1. What are the most common mis-uses of it,

Here are another couple that have come up recently:

Strings are not “fast.” This loop, where the charAt() method is used to retrieve individual characters, will be much slower that a C array or pointer based solution. The “val = “”;” at the end will invoke free(), and is much slower that you’d think.

String val;

void loop() {
    val =  Serial.readStringUntil('\n'); 
    for(int i=0;i<len; i++){
        if(i!=len-1){
            if(val.charAt(i)=='0'){
                // Speed critical code
            }
        }
    }
    //Reset
    val="";
}

Doing String operations in the arguments to print or println is going to be significantly more complex and slower than simply calling print multiple times, PLUS it has the memory fragmentation issues.

Serial.println(String("Last Position: ") + (unsigned long)Y + String(" %"));