Getting rid of String in favor of char s[]

I'm cleaning some example code from a book for my own use by removing String:

WiFiClient client;
char line[250] = ""; // was a String, make it char array

...

//String line = client.readStringUntil('\n');              // don't use String in production code!
strcpy(line, (client.readStringUntil('\n').c_str()));    //  reads String then convert to char[]

It looks like readStringUntil() is inherited from Stream. Does the strcpy() look sufficient to stop the issues with String heap fragmentation or do I need to read byte by byte and manage the lower level details myself. I have a bad feeling that calling readStringUntil() puts something on the heap which is what I want to avoid.

Is there a better way to read char arrays from WiFiClients? A good example?

Have you looked at he serial input basics tutorial. It shows how to read serial input data into a string (null terminated character array). That avoids using the String class altogether so no potenial memory contamination that he String class can cause.

groundFungus pointed you in the right direction, but just to provide some additional information, readBytesUntil() is the non-String equivalent of readStringUntil().

Don't get thrown off by the "bytes" part of the function name. You can use it to fill a char array.

readStringUntil() readBytesUntil() won't cause memory fragmentation, but it blocks the execution of code until the entire input has been read up to the terminator (or until the timeout duration set by setTimeout() passes if the terminator never arrives). For this reason, it's best to read the incoming data one byte at a time, so that the rest of your code can continue to run in the meantime.

Excellent information. Thank you both!

You're welcome.

A correction, which someone was kind enough to point out to me. Above I wrote:

readStringUntil() won't cause memory fragmentation

but I intended to write:

readBytesUntil() won't cause memory fragmentation