A concat variable is causing the whole string to be empty after the first use

I have code that will loop until a specific RFID reader is triggered. The code will then put together a string that contains a string of url variables.
I then concat that string into the http header string

The first time I run the code it works just fine
but if I try to trigger the system again when I try to concat the URL variable into to the HTTP string it seems to make the entire string empty.

void RecordRacer(int track, String car, int go)
{

  {
    String url = "/adddata";
    String FullURL = "";
    String hts = "";
    FullURL = url;
    Serial.println("race is over");
    
   //Loop through each lane
    for (int i = 0; i < 4; i++) {
    
      if(i == 0)//first variable in URL is ? //others are &
      {
      FullURL += "?";
      }
      else
      {
      FullURL += "&";
      }
        //printing for debuging
   //    Serial.print("Lane: ");
   //    Serial.println(FinishOrder[0][i]);
   //    Serial.print("Place: ");
   //    Serial.println(FinishOrder[1][i]);
      //Look in the array for the finish order of each lane
      switch (FinishOrder[1][i]) {
        case 1: //Lane 1
           FullURL += "first="; 
           FullURL += Cars[FinishOrder[0][i]-1]; //Cars are placed in this array by the track ID. Use the finish order array to identify what track a car is on. 
           Serial.print("Car: ");
           Serial.println(Cars[FinishOrder[0][i]-1]);
          Serial.println(FullURL);
          break;
        case 2:
           FullURL += "second=";
           FullURL += Cars[FinishOrder[0][i]-1];    
           Serial.print("Car: ");
           Serial.println(Cars[FinishOrder[0][i]-1]);
           Serial.println(FullURL);
           break;
        case 3:
           FullURL += "third=";
           FullURL += Cars[FinishOrder[0][i]-1];
           Serial.print("Car: ");
           Serial.println(Cars[FinishOrder[0][i]-1]);
           Serial.println(FullURL);
          break;
        case 4:
           FullURL += "fourth=";
           FullURL += Cars[FinishOrder[0][i]-1];
           Serial.print("Car: ");
           Serial.println(Cars[FinishOrder[0][i]-1]);
           Serial.println(FullURL);
          break;
        default:
          // statements
        break;
      }
     }
   
     //Reset our variables for the next race
      go = 0;
      Cars[0] = "0";
      Cars[1] = "0";
      Cars[2] = "0";
      Cars[3] = "0";
	  Serial.print(FullURL); //This URL is constructed correctly each time

           //if I hardcode the HTTP request string it works fine every time
      //String ht = "GET /adddata?second=4327d72585881&first=41d7d72585881&fourth=0&third=4327d72585881 HTTP/1.1\n"
        //             "Host: <site>.azurewebsites.net\n"
          //           "Connection: close\n\n"; 

      //This is the string that works the first time I try to create it, but each time after will end up not printing anything to serial and the item will not be recorded 
               hts = "GET "+FullURL+" HTTP/1.1\n"
                     "Host: <site>.azurewebsites.net\n"
                     "Connection: close\n\n"; 
      
      Serial.println(hts); //prints fine the first time, but the second time is empty
      
    
      clientDemo(hts);  //Calls the function to post the data to the website
  }  
}

Without seeing the full code, the first suspect is the use of the String (capital S) class and its associated possible memory issues.

Note that symptoms often can be the result of issues in other parts of the code; e.g. writing outside the boundaries of an array somewhere.

My guess is that memory is getting fragmented by all those Strings, and it can't allocate the buffer for String after the first time through. Failed attempts to allocate the buffer for a String result in said String being empty, so that's consistent.

This is a prime example of why String (and dynamic memory allocation in general) shouldn't be used on a microcontroller with 2k of RAM.

The symptoms are indeed those of String causing heap fragmentation. However, you might be able to get away with it by the following.

  1. declare FullURL and hts as a global variables .
  2. in setup(), reserve the maximum space for these which they will ever use, say , 100 and 200 bytes respectively :
FullURL.reserve( 100 ) ;
hts.reserve( 200 ) ;
  1. optimise RecordRacer() to use only “reserved” Strings
  2. later optimise to reduce to one “reserved” String and use char arrays for the fixed parts.
  3. even later optimise to remove the Strings completely.

Thanks everyone - I started the process of converting everything to Chars, which honestly was something I had been trying to avoid because I don't really know how to use them :) But it is something that I should learn so I did. So far I have gotten to run and print to serial - Still have somethings to work through so I may be back.

Let me know if I should start a new thread on this - I this I figured out how to make everything with chars

I can print out hts and it looks correct in serial.print

  strcat(hts,FullURL);
      strcat(hts," HTTP/1.1\n");
      strcat(hts,"Host: hotwheelracing.azurewebsites.net\n");
      strcat(hts,"Connection: close\n\n"); 
      //strcat(hts,"\0"); 
      
      Serial.println("add to http");
      Serial.println(hts);

      PostData(hts);
void PostData(char httpRequest)
{
  // To use the ESP8266 as a TCP client, use the 
  // ESP8266Client class. First, create an object:
  ESP8266Client client;
   
  // ESP8266Client connect([server], [port]) is used to 
  // connect to a server (const char * or IPAddress) on
  // a specified port.
  // Returns: 1 on success, 2 on already connected,
  // negative on fail (-1=TIMEOUT, -3=FAIL).
  int retVal = client.connect(destServer, 80);
  if (retVal <= 0)
  {
    Serial.println(F("Failed to connect to server."));
    return;
  }

  // print and write can be used to send data to a connected
  // client connection.
  Serial.println("right before request"); //debug print
  Serial.println(httpRequest);
  client.print(httpRequest);

  // available() will return the number of characters
  // currently in the receive buffer.
  while (client.available())
    Serial.write(client.read()); // read() gets the FIFO char
    Serial.write("made it");
  
  // connected() is a boolean return value - 1 if the 
  // connection is active, 0 if it's closed.
  if (client.connected())
    client.stop(); // stop() closes a TCP connection.


}

I now want to pass this into my function that will post to my website

as soon as I add PostData(hts); to the code I get gibberish in my serial monitor.

I am sure that I did’nt create my chars correctly, I can post all my code if needed. But why would the addition of a function call cause so much chaos? it does’nt even properly do the serial.print(hts) action, even though that is before the function call.

You need to change your function prototype to

void PostData(const char* httpRequest)

This way, it can accept an array of chars (a c-string). What is the data type of hts? Maybe you need to change this as well.

Perfect! Thanks for the help there!

Okay I am soooo close :slight_smile: Here is what I hope is my last issue.

//go is a variable that if set to true will record the race
void RecordRacer(int track, char* car, int go)
{
         

//Which car is on which track, fill the array
switch (track) {
  case 0:
    strcpy(Cars[track],car);
      Serial.print("Car: ");
      Serial.println(car);
      Serial.print("Track: ");
      Serial.println(track);
    
    break;
  case 1:
    strcpy(Cars[track],car);
    Serial.print("Car: ");
      Serial.println(car);
      Serial.print("Track: ");
      Serial.println(track);
    //Serial.println(Cars[track]);
    break;
  case 2:
    strcpy(Cars[track],car);
    Serial.print("Car: ");
      Serial.println(car);
      Serial.print("Track: ");
      Serial.println(track);
    //Serial.println(Cars[track]);
  break;
  case 3:
    strcpy(Cars[track],car);
    Serial.print("Car: ");
      Serial.println(car);
      Serial.print("Track: ");
      Serial.println(track);
    //Serial.println(Cars[track]);
  break;
  default:
    // statements
  break;
    }
    for (int i = 0; i < 4; i++)
    {
     // Serial.print("Car: ");
     // Serial.println(Cars[i]);
     // Serial.print("Track: ");
     // Serial.println(i+1);
      
    }
if(go) //if race is over start here
  {
    char url[9] = "/adddata";
    char FullURL[100] = "";
    char hts[200] = "GET ";
    strcpy(FullURL, url);
    //FullURL[8] = '\0';
    Serial.println("race is over");
    
   //Loop through each lane
    for (int i = 0; i < 4; i++) {
    
      if(i == 0)//first variable in URL is ? //others are &
      {
        strcat(FullURL,"?");
      }
      else
      {
          if(strlen(Cars[FinishOrder[0][i]-1])== 0)
            {
            } 
          else
            {
              strcat(FullURL,"&");
            }
        
      }
       
      
        //printing for debuging
       Serial.print("Lane: ");
       Serial.println(FinishOrder[0][i]);
       Serial.print("Place: ");
       Serial.println(FinishOrder[1][i]);
      //Look in the array for the finish order of each lane
     switch (FinishOrder[1][i]) {
        case 1: //Lane 1
          if(strlen(Cars[FinishOrder[0][i]-1])== 0)
          {
          //if no racer dont add to url  
          }    
          else
          {
             strcat(FullURL,"first=");
             strcat(FullURL,Cars[FinishOrder[0][i]-1]);    
             Serial.print("Car: ");
             Serial.println(Cars[FinishOrder[0][i]-1]);
             Serial.println(FullURL);
          }
          break;
       case 2:
         if(strlen(Cars[FinishOrder[0][i]-1])== 0)
         {
         }    
         else
         {
            strcat(FullURL,"second=");
            strcat(FullURL,Cars[FinishOrder[0][i]-1]);    
            Serial.print("Car: ");
            Serial.println(Cars[FinishOrder[0][i]-1]);
            Serial.println(FullURL);
         }
         break;
       case 3:
         if(strlen(Cars[FinishOrder[0][i]-1])== 0)
         {
         }    
         else
         {
           strcat(FullURL,"third=");
           strcat(FullURL,Cars[FinishOrder[0][i]-1]);
           Serial.print("Car: ");
           Serial.println(Cars[FinishOrder[0][i]-1]);
           Serial.println(FullURL);
         }
         break;
       case 4:
        if(strlen(Cars[FinishOrder[0][i]-1])== 0)
        {
        }    
        else
        {
          strcat(FullURL,"fourth=");
          strcat(FullURL,Cars[FinishOrder[0][i]-1]);
          Serial.print("Car: ");
          Serial.println(Cars[FinishOrder[0][i]-1]);
          Serial.println(FullURL);
        }
         break;
        default:
          // statements
        break;
      }
     }
   
      //This string always shows what I expect
      Serial.println(FullURL);

      strcat(hts,FullURL);
      strcat(hts," HTTP/1.1\n");
      strcat(hts,"Host: hotwheelracing.azurewebsites.net\n");
      strcat(hts,"Connection: close\n\n"); 
      
      Serial.println("add to http");
      //This will display wierd characters in what use to be the FullURL part of the now bigger string
      Serial.println(hts);

      //Post to website - if this is commented out hts prints just fine
      //PostData(hts);
     
     //Reset our variables for the next race
      go = 0;
      memset(FullURL, 0, sizeof(FullURL));
      memset(Cars, 0, sizeof(Cars));
      memset(hts, 0, sizeof(hts));
       
      
  }

}

when I print to serial I get this for first URL
/adddata?&first=41c7d72585881 (yes I know I have an & to remove…)

add to http

After I uncomment the call to PostData() - my char starts to get corrupted

GET /adddata?&first=41c7d7-^85881 HTTP/1.1
Host: hotwheelracing.azurewebsites.net
Connection: close

void PostData(const char* httpRequest)
{
  // To use the ESP8266 as a TCP client, use the 
  // ESP8266Client class. First, create an object:
  ESP8266Client client;
   
  // ESP8266Client connect([server], [port]) is used to 
  // connect to a server (const char * or IPAddress) on
  // a specified port.
  // Returns: 1 on success, 2 on already connected,
  // negative on fail (-1=TIMEOUT, -3=FAIL).
  int retVal = client.connect(destServer, 80);
  if (retVal <= 0)
  {
    Serial.println(F("Failed to connect to server."));
    return;
  }

  // print and write can be used to send data to a connected
  // client connection.
  //Serial.println("right before request");
  //Serial.println(httpRequest);
  client.print(httpRequest);

  // available() will return the number of characters
  // currently in the receive buffer.
  while (client.available())
    Serial.write(client.read()); // read() gets the FIFO char
    
  // connected() is a boolean return value - 1 if the 
  // connection is active, 0 if it's closed.
  if (client.connected())
    client.stop(); // stop() closes a TCP connection.


}

After I uncomment the call to PostData() - my char starts to get corrupted

Is it really too much trouble to use the proper type in your problem description? What char are you talking about? It is far more likely that you have a char ARRAY!

Its only hard because I am learning the terminology, thank you for the correction. But yes my char array hts is the one that is showing weird characters when I print to serial once I pass it to PostData, where it comes in as const char* httpRequest. Which from my understanding is a pointer to the start of the memory chunk that holds hts.

I also forgot to post that these variables are declared at the top of the sketch which I believe are called global variables if that helps

char Cars[4][25] = {0,0,0,0};

//first line is lane, second is place - use 0 if there if lane is not used
//Communication from second arduino will be needed this is hard coded for now
int FinishOrder[2][4] = {
  {1,  2,  3, 4  },
  {2,  1,  4, 3  } 
};
//first line is lane

No. That is not correct, or is not needed. The index into a 1D array would be the lane number (starting at 0). There is no reason to use a 2D array so that the [n][0]the element of the array is n+1.

The initial values in the array make no sense.

you really need to take your snippets to http://snippets-r-us.com.