String Concatenation

All,
Its generally never happened that I don't find an answer to my problem, but this time I have, and unfortunately for something as simple as String Concatenation. My programming skills are limited, probably that's the reason why I haven't been able to figure it out yet, hence the shout for help.

So I'm using ESP8266 for integrating some sensors and uploading data to my server. I'm having problems concatenating multiple strings - combination of fixed text and variable. Ofcourse I did do a search and I tried quite a few combinations, but none to any good. Code is as below:

 //HTTP procedure begins

    char PostStr1[ ] = "=records&data[]=";
    char ndate[ ] = "2018-01-22,";
    char ntime[ ] = "16:05:18,";
    char nvar[ ] = "A,";
    char PostString[ ] = "";

      String PostString = "table"+ PostStr1 + ndate + ntime + secSince + var1 + var2 + var3 + var4 + var5; 
      Serial.println(PostString);
      Serial.println();
      http.begin("http://my.webserver.com/uploadD.php");               //this is the actual php file that is called for upload
      http.addHeader("Content-Type", "application/x-www-form-urlencoded");    //This content type is needed for IoT upload API
      Serial.print("HTTP Response code = ");       
      Serial.println(httpCode);
      Serial.print("Application Repsonse: ");
      http.writeToStream(&Serial);
      Serial.println();
      http.end();

This is not working. It gives an error saying "conflicting declaration String PostString"

I even tried:

String PostString = ("table") + String PostStr1 + ndate + ntime + secSince + var1 + var2 + var3 + var4 + var5;

Got the same error.

PostString = ("table") + String PostStr1 + ndate + ntime + secSince + var1 + var2 + var3 + var4 + var5;

Got the error "expected primary-expression before 'Poststr1'"

I'm using Arduino 1.8.5 IDE.

Apologies if this might be a stupid silly query which might have been answered already. Rest of my code is ready and I'm not stuck only at this issue. Thanks a ton in advance.

-Deepak

char PostString[ ] = "";

      String PostString =

That was easy

Suggest you lose the Strings (big S), and use the standard strcat() function...
Everything will be better.
!

It might seem like it takes longer, but with the limited memory resources of micro controllers maybe you should just Serial.print() each part that you are trying to concatenate and Serial.println() the last part, or twice after the last part. This will save you the memory overhead of having to copy multiple pieces of memory into a second piece of memory.

So, instead of:

      String PostString = "table"+ PostStr1 + ndate + ntime + secSince + var1 + var2 + var3 + var4 + var5; 
      Serial.println(PostString);
      Serial.println();

You would have:

      Serial.print("table");
      Serial.print(PostStr1);
      Serial.print(ndate);
      Serial.print(ntime);
      Serial.print(secSince);
      Serial.print(var1);
      Serial.print(var2);
      Serial.print(var3);
      Serial.print(var4);
      Serial.println(var5); 
      Serial.println();

Yes, it takes up more lines of code, but you remove the need for a buffer. (And remove the need to decide how large to make the buffer only to realize several iterations of code down the line that the buffer needs to be larger).

The (nearly universal) advice to eschew using the capital "S" String objects is because they have a tendancy to fragment the limited memory. Microcontrollers, especially the ones commonly used in ArduinoLand(tm), have no way of cleaning up fragmented memory. So the code starts working well, but will eventually crash when the free memory runs out (actually variable space collides with the stack...).

Sembazuru:
The (nearly universal) advice to eschew using the capital "S" String objects is because they have a tendancy to fragment the limited memory. Microcontrollers, especially the ones commonly used in ArduinoLand(tm), have no way of cleaning up fragmented memory. So the code starts working well, but will eventually crash when the free memory runs out (actually variable space collides with the stack...).

Worse still, the most frequent use of Strings - to repeatedly concatenate with other strings to build one long one - is the way of using Strings that's worst in terms of causing this.

CtrlAltElite:

char PostString[ ] = "";

String PostString =


That was easy

I have tried the same, but still doesn't work. Unless I missed something?

Sembazuru:
It might seem like it takes longer, but with the limited memory resources of micro controllers maybe you should just Serial.print() each part that you are trying to concatenate and Serial.println() the last part, or twice after the last part. This will save you the memory overhead of having to copy multiple pieces of memory into a second piece of memory.

So, instead of:

      String PostString = "table"+ PostStr1 + ndate + ntime + secSince + var1 + var2 + var3 + var4 + var5; 

Serial.println(PostString);
     Serial.println();




You would have:


Serial.print("table");
     Serial.print(PostStr1);
     Serial.print(ndate);
     Serial.print(ntime);
     Serial.print(secSince);
     Serial.print(var1);
     Serial.print(var2);
     Serial.print(var3);
     Serial.print(var4);
     Serial.println(var5);
     Serial.println();




Yes, it takes up more lines of code, but you remove the need for a buffer. (And remove the need to decide how large to make the buffer only to realize several iterations of code down the line that the buffer needs to be larger).

The (nearly universal) advice to eschew using the capital "S" String objects is because they have a tendancy to fragment the limited memory. Microcontrollers, especially the ones commonly used in ArduinoLand(tm), have no way of cleaning up fragmented memory. So the code starts working well, but will eventually crash when the free memory runs out (actually variable space collides with the stack...).

Thanks. The Serial is only for debugging right now so that i can see and ensure how PostString is being constructed. I'll remove it once the code is working clean. But yes, I generally print on Serial the way you mentioned when I have serial operations

lastchancename:
Suggest you lose the Strings (big S), and use the standard strcat() function...
Everything will be better.
!

Some of my variables are int and some are float/long float. I tried with a simple code as below:

char PostStr1[ ] = "=records&data[]="; char ndate[ ] = "2018-01-22,"; char ntime[ ] = "16:05:18,"; char nvar[ ] = "A,"; char PostString[ ] = ""; int var1 = 10; float var2 = 13.5;

strcat(PostString,PostStr1);
strcat(PostString,ndate);
strcat(PostString,"table");
strcat(PostString,var1);
strcat(PostString,var2);

This did not work. I get an error:
/tmp/012337249/sketch_sep14a/sketch_sep14a.ino:29:29: error: cannot convert 'float' to 'const char*' for argument '2' to 'char* strcat(char*, const char*)'

exit status 1

I suspect I'll have to convert my non-string variables to string?

Well, again, obviously - var2 is a float, not a string, so you can't use strcat (the "str" is an abbreviation of "string").

dtostrf is one way you could do it.

Consecutive prints is another way.

Thanks.

    char PostStr1[ ] = "=records&data[]=";
    char ndate[ ] = "2018-01-22,";
    char ntime[ ] = "16:05:18,";
    char nvar[ ] = "A,";
    char PostString[ ] = "";
    int var1 = 10;
    float var2 = 13.50;
    char var2str[5];

      dtostrf(var2, 5, 2, var2str);
      strcat(PostString,PostStr1);
      strcat(PostString,ndate);
      strcat(PostString,"table");
      strcat(PostString,var1);
      strcat(PostString,var2str);

This compiles fine now. Tried this on the web editor and looks ok. Will test it on the board and see if all goes well. Thanks for the help folks.

 int var1 = 10;
      strcat(PostString,var1);

Do you remember what I wrote earlier about the "str" being short for "string"?

 float var2 = 13.50;
    char var2str[5];

var2str is too short to hold "13.50".

This post may be useful... to build up a string

Using sprintf() Example

sprintf(buff, "%f%f", var1, var2) was returning "%f%f" as output when I printed buff, because I read that %f is still not supported in Arduino IDE. dtostrf() and strcat() were also not working as expected even after increasing the size of the array.

I finally tried this:

    char PostString[ ] = "";
    float var1 = 10.59;
    float var2 = 13.50;
 
   String PostString[] = String(var1) + "," + String(var2);
   Serial.println(PostString);

And it worked with the expected output. Its probably because of my limited skills that I could not get the other codes right, but this above "S" code worked for me. I'll do a longevity test to see if all goes well and there are no leaks.

Regards,
Deepak

deepak4you:
... I could not get the other codes right, but this above "S" code worked for me.

Really, you couldn't do this:

CtrlAltElite:
Consecutive prints is another way.

He was telling you to do this:

   float var1 = 10.59;
   float var2 = 13.50;
 
   Serial.print( var1 );
   Serial.print( "," );
   Serial.println( var2 );

No String class, no sprint format issues nor RAM buffers, and no longevity issues. And be sure to compare the program sizes with and without String. Your sketch should be at least 1600 bytes smaller.

You do not have to build one big string for printing. Just print the pieces.

-dev:
Really, you couldn't do this:
He was telling you to do this:

   float var1 = 10.59;

float var2 = 13.50;

Serial.print( var1 );
  Serial.print( "," );
  Serial.println( var2 );



No `String` class, no `sprint` format issues nor RAM buffers, and no longevity issues. And be sure to compare the program sizes with and without `String`. Your sketch should be at least 1600 bytes smaller.

You do not have to build one big string for printing. **Just print the pieces.**

Chief, sending the values to Serial doesn't help me because I need to build up a string to pass it to the POST variable in the HTTP request. I have tried various combinations using strcat(), String, concat, sprintf, dtostrf and none of them seem to build me a single string.

Taking the stripped down code below, all I want to do is:

void loop() {
  // put your main code here, to run repeatedly:
Serial.flush();
char param [] = "data=";
char comma = ",";
float var1 = millis()/79.63;
float var2 = millis()/57.39;
float var3 = millis()/23.17;
float var4 = millis()/97.73;
char buff[30];
char PostString [] = "";
delay(2000);
yield();
}

PostString should be a concatenation of: param,var1,comma,var2,comma,var3,comma,var4 in this sequence. Once that string is built, I can directly post that string over HTTP as below:

int httpCode = http.POST(PostString);

Again, my programming skills are limited probably that's why I haven't been able to make any of the available options work.

Or, is there a way to pass individual strings in http.POST() like http.POST(param + comma + var1 + comma + var2), or something on similar lines?

All my sensors are done and I'm badly stuck only with this bit to complete my code :frowning:

I need to build up a string to pass it to the POST variable in the HTTP request.

Argh, that stupid String interface!

Ok, since I'm not qoing to rewrite the HTTP class (and related classes) to Not Use String, let's do the best we can...

In your case, we can pre-allocate the String memory. This avoids many allocations during "+" operations when building the message. But then, we should make a good guess about the final size. Perhaps something like this:

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

  // Wait a random amount of time
  Serial.print( "Enter something: " );
  while (not Serial.available())
    ;  // waiting...

  float var1 = millis()/79.63;
  float var2 = millis()/57.39;
  float var3 = millis()/23.17;
  float var4 = millis()/97.73;

  const char   PARAM[]         = "data=";
  const size_t MAX_VAR_STRING  = sizeof("12345678.12")-1;
  const size_t EXTRA           = 8;
  const size_t ALLOCATION_SIZE = sizeof( PARAM )-1 + 4 * MAX_VAR_STRING + 3 * sizeof(',') + EXTRA;

  String PostString;

  PostString.reserve( ALLOCATION_SIZE );   // pre-allocate PostString memory

  PostString = PARAM;
  PostString += var1;  // 2 decimal places
  PostString += ',';
  PostString += var2;  // 2 decimal places
  PostString += ',';
  PostString += var3;  // 2 decimal places
  PostString += ',';
  PostString += var4;  // 2 decimal places

  Serial.print( "Requested allocation size = " );
  Serial.println( ALLOCATION_SIZE );

  Serial.print( "Actual PostString length = " );
  Serial.println( PostString.length() );
  
  Serial.println( "PostString = " );
  Serial.println( PostString );

}

void loop() {}

This adds up the sizes of the pieces to determine a maximum size. Notice that it uses double-quoted constants in two ways: for one piece to be added (e.g., PARAM), or as an example of the maximum size of one piece (e.g., MAX_VAR_STRING).

Then it adds up all the sizes (plus a little extra) and calls the reserve method to pre-allocate that much memory.

This technique helps reduce the probability of memory fragmentation caused by String reallocations. There are additional guidelines that should be followed.

For example, you could create some of these Strings during setup. This creates them once at program startup, instead of creating & destroying every time you do a POST. The PostString could be pre-allocated in setup and assigned before doing the POST.

Or, you could put all of the http.xxxx calls into a routine, so that all the Strings created for those calls would get destroyed at the end of that routine.

It's hard to make further suggestions for safe String usage without the entire sketch. This is an advanced topic.

That was great info, thanks. I'll try out that code. Infact I was so dejected that I was thinking of writing my own code to convert float/int to char one byte at a time and store it in the final PostString. Your approach gives me some direction. I'll post the whole sketch soon so that we can explore some more optimisations.

Also, I will indeed be calling a function just before the end of the loop to build the PostString and post the content to my webserver. Might be that will help, as you pointed it out.

Will update soon.

Regards,
Deepak