Issues with Building long Strings.

Hi Guys,

I have an issue with building long strings and printing them to Serial.

To explain the code below real quick. I am getting a bunch of different sensor values and storing them all into strings, I am then adding all those strings together to create one long string value that I can send where ever I need to.

The Problem:

When I run the sketch and check the Serial monitor, the string is built and prints as it is supposed to, but from the second loop and forever after - the Serial prints out just half of the string from "$C" on wards.

Below is a minimal sketch with test values to show this problem

//These Strings are updated along the course of the loop and then inserted into the string that is made in buildString().

String ECReading = "TestECReading";
String RainReading = "TestRainReading";
String VoltageReading = "TestVoltageReading";
String GSMSignal = "$GSMS";
String NodeID = "$NID";
String TimeDate = "$TD";
String ProbeID = "$ID";

// These String Values are updated at different intervals by getting the values via Serial. They too are also thrown in the main report string in buildString().
String temperatureReading = "-13.48605,- 7.884103,-10.37,- 13.05851,-8.596266,-13.48605,- 7.884103,-10.37,- 13.05851,-8.596266,-13.48605,- 7.884103,-10.37,- 13.05851,-8.596266";
String moistureReading = "-13.48605,- 7.884103,-10.37,- 13.05851,-8.596266,-13.48605,- 7.884103,-10.37,- 13.05851,-8.596266,-13.48605,- 7.884103,-10.37,- 13.05851,-8.596266";

String reportString = "";

void setup(){
Serial.begin(9600);

}

void buildString(){
  reportString = String("!!") + "," + "PS" + "," + "0" + "," + ProbeID + "-" + NodeID + "_" + TimeDate + "," + "$A" + "," + moistureReading + "," + "$B" + "," + temperatureReading + "," + "$C" + "," + ECReading + "," + "$D" + "," + RainReading + "," + VoltageReading + "," + GSMSignal + "," + "!";
  Serial.println(reportString);
  reportString = ""; // clear for the next String build
}

void loop(){

 buildString();
 delay(5000);

}

I KNOW this is NOT an efficient way to do this, and its partly the problem as to why I am getting this issue. I know I am meant to be using char arrays but I am not sure how they work for my situation (some values not being const strings). If anyone has an examples that would work best for me, that would be so great!

Otherwise, could anyone show me where I am going wrong and how to make this more efficient?

Thanks!

Regards,
Bren

You make it more efficient by:

  1. Using char arrays, rather than String
  2. NOT building a single large string. Instead, write a function that outputs the individual strings in the desired order. If you need to send this data to different devices, then pass a reference to the device to that function. Creating that one large string is a pure waste of time and memory.

Regards,
Ray L.

BrenMaarten:
I KNOW this is NOT an efficient way to do this, and its partly the problem as to why I am getting this issue. I know I am meant to be using char arrays but I am not sure how they work for my situation (some values not being const strings). If anyone has an examples that would work best for me, that would be so great!

sprintf()

Think about it: you're sending characters out at a rate of just less than one character per millisecond; whatever is receiving them doesn't care if they were sent as one long string or 200 individual characters.

It is not a good idea to use the String (capital S) class on an Arduino as it can cause memory corruption in the small memory on an Arduino. Just use cstrings - char arrays terminated with 0.

...R

RayLivingston:
You make it more efficient by:

  1. Using char arrays, rather than String
  2. NOT building a single large string. Instead, write a function that outputs the individual strings in the desired order. If you need to send this data to different devices, then pass a reference to the device to that function. Creating that one large string is a pure waste of time and memory.

Regards,
Ray L.

Thanks Ray,

As I said, I know I need to use perhaps a char array instead and use a for loop and a function to produce the string in a certain order. But aren't char array's used for constants? ie. strings for LCD Screen Menu's etc?
Can I still use it if my strings are going to be changing after every few minutes?

Unfortunately, I have to build a long string at the end of the day because I need to write it to a .csv file for saving.

char arrays can be constant but do not have to be. A char array would be better than a String.

BrenMaarten:
As I said, I know I need to use perhaps a char array instead and use a for loop and a function to produce the string in a certain order. But aren't char array's used for constants? ie. strings for LCD Screen Menu's etc?
Can I still use it if my strings are going to be changing after every few minutes?

hmmmm...

would anyone bother with an LCD display that could only display one thing?

I have to build a long string at the end of the day because I need to write it to a .csv file for saving.

Nope. Just like printing...

  Serial.print( F("Sensor1: ") ); // using the F macro here saves RAM
  Serial.println( sensor1Value );

  Serial.print( F("Sensor2: ") );
  Serial.println( sensor2Value );

  Serial.print( F("Sensor3: ") );
  Serial.println( sensor1Value );

... the SD card does not know how many times you called print. Printing the pieces works for the CSV file, too:

  file.print( sensor1Value );
  file.print( ',' );
  file.print( sensor2Value );
  file.print( ',' );
  file.println( sensor1Value );

You don't even need a character array. It's way more efficient to hold on to the numeric values, rather than the character representations of those values:

int sensor1Value;
float sensor2Value
unsigned long sensor3Value;

That only uses 10 bytes for all 3 values. In character form, those values might be "32767", "123.4567" and "2147483647", a total of 27 bytes. If you are also saving labels, it's even worse.

Hi Guys,

Thanks everyone for the replies. I have now been reading more about Strings vs strings[] and sprintf.

@/Dev, You have a really good point actually. If I keep my values as is, and print them without having to save them as a string first, makes it way more efficient. I just tried it now instead and it prints to Serial in which case I can also save to file. Thanks for that tip!

My reason for wanting to save it all in 1 string or array was because in the future with this project I may need to send all that data via RF every 20mins or so. My logic was that If I could just bundle up all that data into a block of data then send the whole block over in which case I would assume you would then have to use a char array to make it the data as compact as possible?

Look at it this way. A byte can contain values from 0 to 255. If you store that in a char array, you need between 1 and 3 bytes. An int (2 bytes) can contain values from -32768 to 32767 and you need between 1and 6 bytes to store that in a char array.

What is more compact :wink:

If you want to collect data first (e.g. one reading of several analog inputs for twenty minutes), you better store it in binary format in arrays (one per input) and loop through those arrays when you want to send it.

sterretje:
Look at it this way. A byte can contain values from 0 to 255. If you store that in a char array, you need between 1 and 34 bytes. An int (2 bytes) can contain values from -32768 to 32767 and you need between 1and 67 bytes to store that in a char array.

Don't want to forget the nulls...

Regards,
Ray L.

It's only one nul (or is it null ?) for the full character array that contains multiple values :wink:

It's only one nul (or is it null ?) for the full character array that contains multiple values

Well,youprobablywantsomekindofdelimeterbetweenvalues,don'tyou?

PaulS:
Well,youprobablywantsomekindofdelimeterbetweenvalues,don'tyou?

notlikethisNULLmaybeyouwantitlikethisNULLnoIdoubtitNULL :smiley:

I did not talk about formatting as that was not relevant in reply #12.