How to replace String objects with char arrays while still using string methods I am running the following code on my ESP8266 (AI-Thinker ESP8266MOD).

I send an HTTP GET request and a pin is set to high for a 1/2 second.

However, after some time (sometimes 1hr, 2hrs, 12hrs, totally random), it stops responding to HTTP requests.
I think it might be because of heap fragmentation due to the String objects I'm using.

Questions:

How can I replace the request (in loop()) and s and text (in GenerateResponse()) objects with  char arrays?
After I replace the String objects with char arrays, how can I use the indexOf() method and + operator on the char arrays?

Will this approach help with heap fragmentation? 

Is it possible to find out if heap fragmentation is the problem?

#include &lt;ESP8266WiFi.h&gt;

const char* ssid = "myWifi";
const char* wifiPassword = "y76ggS";
const char* passwordToOpenDoor = "/81"; //password should begin with a slash

const int doorPin = 5;

WiFiServer server(301); //Pick any port number you like
WiFiClient client;

void setup() {
  Serial.begin(115200);
  delay(10);
  Serial.println(WiFi.localIP());

  pinMode(doorPin, OUTPUT);
  digitalWrite(doorPin, 0);

  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, wifiPassword);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");

  server.begin();
  Serial.println("Server started. Diagnostics info:");
  Serial.println(WiFi.localIP());
}

void loop() {
  client = server.available();
  if (!client) {    
    return;
  }

  while(!client.available()){
    delay(1);  
  }

  String request = client.readStringUntil('\r'); 
  client.flush();

  Serial.println(request);  
  if (request.indexOf(passwordToOpenDoor) != -1) { //Is password correct?    
    GenerateResponse("Password is correct");
    OpenDoor();    
  }
  //Got a GET request and it wasn't the favicon.ico request, must have been a bad password:
  else if (request.indexOf("favicon.ico") == -1) {  
    GenerateResponse("Password is incorrect.");
  }  
}

void OpenDoor() {
  digitalWrite(doorPin, 1);
  delay(500);
  digitalWrite(doorPin, 0);
}

void GenerateResponse(String text) {
  Serial.println(text);
  String s = "HTTP/1.1 200 OK\r\n";
  s += "Content-Type: text/html\r\n\r\n";
  s += "&lt;!DOCTYPE HTML&gt;\r\n&lt;html&gt;\r\n";
  s += "&lt;br&gt;&lt;h1&gt;&lt;b&gt;" + text + "&lt;/b&gt;&lt;/h1&gt;";
  s += "&lt;/html&gt;\n";
  client.flush();
  client.print(s);
  delay(1);
}
You already received good answer about some general ideas for
replacing String objects with C strings. Here I will try to add some
more tricks more specifically targeted to your actual situation.

I can see two places in your program where the use of String shines by
its convenience, and replacing it with C strings will require some
effort. The first is the use of Stream::readStringUntil(char) for
getting the first request line. Here
I see no better option (see edit below) than reading
the stream one character at a time, and putting those characters into an
array:

const size_t input_buffer_length = 256;

// Read a line of text up to the first '\r'.
// Returns a NUL-terminated string, without the final '\r',
// into a statically allocated buffer.
// Warning: this never times out.
const char *readline(Stream &amp;input)
{
  static char buffer[input_buffer_length];
  size_t pos = 0;  // writing position within the buffer
  int c;           // current character
  while ((c = input.read()) != '\r') {
    if (c &gt;= 0 &amp;&amp; pos &lt; sizeof buffer - 1) {
      buffer[pos++] = c;
    }
  }
  buffer[pos] = '\0';  // terminate the string
  return buffer;
}


You would use it like this:

const char *request = readline(client);


For more robustness, you may want to add a timeout. Note also that this
implementation is no reentrant, as it uses a static buffer. This is not
an issue for your use case.

Edit: As noted by hcheung in a comment, you do not need to implement
this readline() function, as you can use
Stream::readBytesUntil(), which handles the timeout
and is provided by the Arduino core:

char buffer[input_buffer_length];
client.readBytesUntil('\r', buffer, input_buffer_length);


The other place is the usage of String::operator+=(const char *) for
generating the response. Here I would advice you against using
strcat() or strncat(): these will require extra memory to store the
concatenated string which you probably do not need. Instead, you can
simply print() the pieces one by one:

void GenerateResponse(const char *text) {
  Serial.println(text);
  client.println("HTTP/1.1 200 OK");
  client.println("Content-Type: text/html");
  client.println();
  client.println("&lt;!DOCTYPE HTML&gt;");
  client.println("&lt;html&gt;");
  client.print("&lt;br&gt;&lt;h1&gt;&lt;b&gt;");
  client.print(text);
  client.println("&lt;/b&gt;&lt;/h1&gt;&lt;/html&gt;");
  client.flush();
  delay(1);
}


Alternatively, you can make use of the implicit concatenation of string
literals in order to reduce the number of calls to client.print():

void GenerateResponse(const char *text) {
  Serial.println(text);
  client.print(
      "HTTP/1.1 200 OK\r\n"
      "Content-Type: text/html\r\n"
      "\r\n"
      "&lt;!DOCTYPE HTML&gt;\r\n"
      "&lt;html&gt;\r\n"
      "&lt;br&gt;&lt;h1&gt;&lt;b&gt;"
  );
  client.print(text);
  client.print("&lt;/b&gt;&lt;/h1&gt;&lt;/html&gt;\r\n");
  client.flush();
  delay(1);
}