Simple String memory management question

Hi Guys.

I'm fairly new to arduino.
I've figured out that I have limited memory to work with and have moved all my static strings to progmem.
Given this [pseudo/sample] code, do I need to do anything with line to clean it's memory up, or do we have a gc? and I don't need to worry?
My program (700 lines now and counting) keeps stopping execution and I'm trying to figure out if I'm leaking memory or just close to the limit

To summarize, readLineFromSerial either returns a line of data if it has received one, or fills the buffer with what is available (if it can)
When a linefeed arrives, it is yeilded as a String for processing by another function
Otherwise, an empty string is returned.

I need to know if I need to clean the String instances I am creating inside readLineFromSerial up at the end of the loop()

loop()
{
     String data = readLineFromSerial();
     if(data != String(""))
     {
     processLineFromSerial(data)... //sample, no implementation
     }
     delay(250)
}

char[100] buffer;
int index;
String readLineFromSerial()
{
    bool linefeed = false;
     while(Serial.available())
     {
         int c = Serial.read();
         if(index >= 99)
         { break; }
         if(c == 13)
         {
             linefeed = true;
             break;
         }else{
           buffer[index++] = c;
         } 
     }
     if(linefeed)
     {
         buffer[index] = '\0';
         index = 0;
         String data = String(buffer);
         return data;
     }
     return String("");
}

Well!!!!

return String("");
String data = String(buffer);
         return data;

If you program like that, you may have issues with the fact that the strings you are working with are locally generated and destroyed when your code executes the return, so exactly what were you hoping to SAFELY return ?
because if you return something like that and it gets over written so that the terminating '0x0' is missing, its gonna be a very long string of something......

Simple String memory management question

The simple answer, which you would eventually arrive at on your own, is to quit using Strings.

hardcore:
Well!!!!

return String("");
String data = String(buffer);

return data;




If you program like that, you may have issues with the fact that the strings you are working with are locally generated and destroyed when your code executes the return, so exactly what were you hoping to SAFELY return ?
because if you return something like that and it gets over written so that the terminating '0x0' is missing, its gonna be a very long string of something......

That was pseduo code, the real code makes sure the null is always put on under all scenarios (and the static String("") will be null terminated)
Are you saying that the String instance data that is created inside readSerialLine doesn't transfer ownership of the pointer to the calling function on return?

The code seems to work okay, most of the time so I didn't think that would be an issue

Lets assume then, that that is the case - so I move the definition of String data to the main loop and then pass it into readSerialLine
At the time the loop reaches termination and moves back around and a new instance of String data is created,

Do i need to do anything with the old one, or don't worry and it will get cleaned up

PaulS:

Simple String memory management question

The simple answer, which you would eventually arrive at on your own, is to quit using Strings.

The reason I'm using String rather than char[] are a number of reasons

  1. Easy to cast to an integer
  2. Easy to concatenate
  3. Substring & StartsWith
  4. Variable length - presume I can use something like strcmp with two differently sized buffers though

Yes, all of this can be achieved without using Strings I guess.

This begs the question though, why is it there if I'm not supposed to use it?

I should add that String data is treated as if it was readonly outside of readLineFromSerial

buffer is only used inside of it, it was local to the function however I moved it outside to facilitate multiple calls to readLineFromSerial when all the data wasn't available (up to the next linefeed)
yes, you are right, the null terminator could be overwritten somewhere else

The reason I'm using String rather than char[] are a number of reasons

  1. Easy to cast to an integer

You can not under any circumstances cast a String to an int. It is easy to CONVERT a String to an int, using the toInt() method of the string class. It is easy to convert a string to an int using the atoi() function.

  1. Easy to concatenate

It is easy to add a character to a statically sized char array, too. It is easy to add an array of characters to a string, using strcat().

  1. Substring & StartsWith

There are corresponding string functions.

  1. Variable length - presume I can use something like strcmp with two differently sized buffers though

And it is this very feature that uses up so much memory.

What is sending the Arduino data? Is it really likely to send more than say 80 characters as a packet?

Don't use String. See Five things I never use in Arduino projects | David Crocker's Solutions blog for why not.

Okay, points taken, I'll be rewriting to not use String

The data arriving from the serial line won't be more than 100 characters before a linefeed is encountered, aside from the general hardware communication statements (e.g. AT commands & responses - always short), I control the rest of the protocol.

So if I'm using a statically sized char array as a buffer, and maybe returning a bool from readLineFromSerial if we've got a linefeed and it's okay to process what's in buffer, I can implement all of the logic I require using char handling functions... assuming of course I can figure out how to write those :slight_smile:

assuming of course I can figure out how to write those

The String class source code is available, if you get stuck. Or, we are.

agrath:
Are you saying that the String instance data that is created inside readSerialLine doesn't transfer ownership of the pointer to the calling function on return?

It makes a copy of the class instance, so you get a second pointer. It will work, but as you can imagine this fragments memory pretty quickly.

char[100] buffer;

int index;
String readLineFromSerial()
{
    bool linefeed = false;
    while(Serial.available())
    {
    // blah blah
    }
    return String("");
}

You hardly need to return a String here. The buffer is in global memory, just use that. In other words, once readLineFromSerial returns then voila! The string it read is in "buffer".

char[100] buffer;

Hey, OP. Did you even compile this code? You're C#/Java background is showing.