String manipulation

C makes me feel like an idiot. I guess I'm spoiled by C#. I'm very new to Arduino, and have had some great success, but I am seriously stumbling with string manipulation and conversion from other types. I've done a lot of reading, but I just can't find the perfect solution.

I'm building a project with some weather sensors and an OLED screen. Per the advice of many, I am attempting to avoid use of "String", but so far I have been unable to accomplish this. I'm hoping I can post a few snippets of code, and someone can show me a way to do it better. At that point, I believe I can take these examples and better understand how to manipulate these strings.

My program is pretty large, so I'll focus on the specific parts of code I need help with. Again, my goal is to eliminate the use of String.

double temp = BME280.getTemperatureMostAccurate() * 9 / 5 + 32;
String sbuf;
char screenTemp[25];
sbuf = "Temp: " + (String)BME280.getTemperatureMostAccurate() + "C - " + (String)temp + "F";
sbuf.toCharArray(screenTemp, 25);
writeScreen(screenTemp, 0, 0);

-sbuf is defined first because I use it below this to do the same conversion for humidity and pressure.
-The return of BME280.getTemperatureMostAccurate() is of type double
-writeScreen method is defined as: void writeScreen(char * text, bool clear, bool refresh)

With some examples of how to make this better, I believe it will help me with a couple other spots in my program. Thank you, in advance, for any help!

sprintf(screenTemp, "Temp: %fC - %fF", BME280.getTemperatureMostAccurate(), temp);

static const char t1[] PROGMEM = "Temp: ";
static const char t2[] PROGMEM = "C - ";
static const char t3[] PROGMEM = "F";

  float tempC = BME280.getTemperatureMostAccurate();
  char screenTemp[25];
  strcpy_P(screenTemp, t1);
  dtostrf(tempC, 4, 2, screenTemp + strlen(screenTemp));
  strcat_P(screenTemp, t2);
  dtostrf(tempC * 9 / 5 + 32, 4, 2, screenTemp + strlen(screenTemp));
  strcat_P(screenTemp, t3);
  writeScreen(screenTemp, 0, 0);

septillion:
sprintf(screenTemp, "Temp: %fC - %fF", BME280.getTemperatureMostAccurate(), temp);

Floats with xxprintf() functions don't work "out of the box" with Arduino on AVR processors since the AVR libC tools disable it by default to save code space.

In order to enable it you will have to modify the compiler and link options in the platform.txt file.

--- bill

sprintf(), while it doesn't support floating point numbers, is a very powerful and versatile function. However, if you are only using a small subset of the sprintf() functionality, you can almost always save memory using the straight str*() functions, as Whandall uses. The sprintf() version compiles to 5306 bytes while the other version compiles to 4324 bytes, as suggested below:

void setup() {
  Serial.begin(9600);
  float temp = 32.0;
// septillion(temp);
  Whandall(temp);
}

void loop() {
}

void Whandall(float temp)
{
  static const char t1[] PROGMEM = "Temp: ";
  static const char t2[] PROGMEM = "C - ";
  static const char t3[] PROGMEM = "F";

  char screenTemp[25];
  strcpy_P(screenTemp, t1);
  dtostrf(temp, 4, 2, screenTemp + strlen(screenTemp));
  strcat_P(screenTemp, t2);
  dtostrf(temp * 9 / 5 + 32, 4, 2, screenTemp + strlen(screenTemp));
  strcat_P(screenTemp, t3);
  Serial.println(screenTemp);
}
/*
void septillion(float temp) 
{
  char screenTemp[25];
  Serial.println(temp);
  sprintf(screenTemp, "Temp: %f F", temp);
  Serial.println(screenTemp);
}
*/

Sometime a kilobyte of saved memory can make a difference.

I think the best methode were to add a function to BME280
that returns a value in units of 1/100 (or 1/10) of a degree like

long BME280::getTempIn100thDegrees() {

  return((long)doComplicatedFloatStuff());

}

and insert the dot while printing, so dtostrf would not be needed at all.

Thanks to everyone. I will drill through this stuff and see what I can work out.

My library 'PrintEx' will give you a sprintf that contains floating point support, padding, & precision.

Available from the library manager.

C makes me feel like an idiot. I guess I'm spoiled by C#. I'm very new to Arduino, and have had some great success, but I am seriously stumbling with string manipulation and conversion from other types. I've done a lot of reading, but I just can't find the perfect solution.

Do you have an example of the data received by the arduino and an explanation of what or how you want the data parsed?

Just wanted to thank everyone again for all these suggestions. I finally figured out how to use strcat, as well as the fact that one of my issues while using strcat previously was that I was making buffers the EXACT size of the value. Trying to put 2 chars into a 2 place char array, just doesn't work because of the termination char. Trying to be as memory efficient as possible really bit me in the...

I ran into a serious issue when taking Ethernet information (IP, MAC, DNS, Gateway, etc) and converting it into char to display on OLED screen. After creating a String then looking through each part of the IP, adding it to the string, and adding . for byte separation, I would then convert to char array then send to screen. With 5 IP addresses on the screen, it would crash (restart) almost every time. Ditching String and going with a straight char array and adding to it with strcat, solved all issues.

THANK YOU!!! I believe I'm finally learning something! Now to work on ridding String from the rest of my program.

Congratulations!

You can mess up while using the c-type strings pretty easy,
but once you get it right it's rock solid.

You can do everything right while using String classes,
but the Arduino will stall sooner or later.