Strange hang-ups using String operations and String.toCharArray

My total sketch size is about 28000 bytes and has been working fine for many days. When I add a few String operations and String.toCharArray to the code, it freaks out, where "freaks out" = the Arduino keeps resetting itself and seems to get reset either at the string appending operation or the toCharArray operation.

Here's an excert from the code,

int Year = 11; // The Real-time clock writes to variable Year, as a two-digit int.

void setup() {
Serial.begin(9600);
Serial.println("Debug");
}

void loop() {
String LogFileString = "BTU-20";
String Extension = ".csv";
char LogFileChar[13];  // This will become BTU-2011.csv as a character array

String YearString = String(Year);  // Convert 2-digit integer year to string

LogFileString += YearString;
LogFileString += Extension;
LogFileString.toCharArray(LogFileChar,13);  

// Convert the string to a character array, BTU-2011.csv
// Character arrays are required by SD.open, i.e.
// File dataFile = SD.open(LogFileChar, FILE_WRITE);

Serial.println(LogFileChar);

delay(1000);
  
}

The odd thing is that when I run this sketch by itself, it prints the expected response, BTU-2011.csv. In my 28000 byte code, when I comment out the 3 lines that are the string operators and the toCharArray, my code works as expected. Anybody have any idea what's going on?

I am trying to create a logfile name for SD.open based on the real-time clock year. SD.open insists on having a character array, but I don't want to use a constant like "BTU-2011.csv".

I began efforts to do this another way, as follows,

int Year = 11; // The Real-time clock writes to variable, Year, as a two-digit int.

void setup() {
Serial.begin(9600);
Serial.println("Debug");
}

void loop() {
  int Year = 11;
  char YearChar[3];
  int right_digit;
  int left_digit;

  left_digit = Year / 10;
  right_digit = Year % 10;
  YearChar[0] = left_digit;
  YearChar[1] = right_digit;

  Serial.println(YearChar);
}

but became discouraged when Serial.println(YearChar) printed:
bh
(space)bh
I'd then need to figure out how to append character arrays. At any rate, the first method above seemed like the most straight-forward approach, but I'm stumped.

Anybody have any idea what's going on?

I'm guessing you're running out of RAM, or writing to where you shouldn't be, but seeing just excerpts is a waste of time.

YearChar[0] = left_digit;
  YearChar[1] = right_digit;

  Serial.println(YearChar);

That's not a good idea.

YearChar[0] = left_digit;
  YearChar[1] = right_digit;
  YearChar[2] = '\0';

  Serial.println(YearChar);

Thank you for repling, however nothing gets printed with that null character addition.

If I am infact running out of RAM, maybe I shouldn't be using the String class. Does anybody know how to perform the said operation without String? That is, convert a two digit integer to a 2 element character array, then append this character array to another character array, where

Character array 1 (as a constant): BTU-20
Character array 2 (as a variable): 11
Character array 3 (as a constant): .csv

?

I've been tinkering for hours and getting nowhere.

I never use String.
Have you looked at "strcat" or "sprintf"?

If I am infact running out of RAM, maybe I shouldn't be using the String class.

You absolutely shouldn't.

Does anybody know how to perform the said operation without String?

You haven't clearly defined what "the said operation" is, but string (note the lower case s) has been being performed in C for decades before the String class was developed.

You are free to look in the String.cpp file to find what C functions it is using to perform various string manipulations.

That is, convert a two digit integer to a 2 element character array

itoa() comes to mind.

then append this character array to another character array

strcat() comes to mind.

Or as AWOL points out, sprintf will perform both operations in one step.

AWOL, thank you for your recommendations. I think I'm going to steer clear of the String class.

I've accomplished my goal. For others who have run into this problem and want to be spoon fed,
sprintf() converts a two digit integer (which was a variable, in my case) to a character array
strcat() concatenates character arrays

char PrefixChar[7] = "BTU-20";
char YearChar[3];
char ExtensionChar[5] = ".csv";
char LogFileChar[13];  // This will become BTU-2011.csv as a character array

sprintf(YearChar, "%i", Year); 
LogFileChar[0]='\0';
strcat(LogFileChar, PrefixChar);
strcat(LogFileChar, YearChar);
strcat(LogFileChar, ExtensionChar);

It saved 500 bytes of sketch size compared to using the above String example, but more importantly, the Arduino no longer freaks out (it is stable once again).

char PrefixChar[] = "BTU-20";
char YearChar[3];
char ExtensionChar[] = ".csv";

Let the compiler do the counting for you :wink:

You can set individual characters in a character array:

int Year = 11; // The Real-time clock writes to variable Year, as a two-digit int.
char LogFileChar[] = "BTU-20xx.csv";

void setup() {
Serial.begin(9600);
Serial.println("Debug");
}

void loop() {
LogFileChar[6] =  '0' + ((Year/10)%10);
LogFileChar[7] =  '0' + (Year%10);

Serial.println(LogFileChar);

delay(1000);
}
sprintf(YearChar, "%i", Year);

This probably won't affect you (in this situation), but if you are expecting to get a 2 digit output, you should explicitly ask for 2 digit output.

sprintf(YearChar, "%02i", Year);

The 2 will cause a minimum of 2 digits, and the 0 says that you want the output padded with leading 0s, if required.

John, thank you for this even simplier code. It saved the sketch another 2000 bytes! My sketch is starting to look lean at 26000 bytes now. I had tried something like this earlier but got blank characters on the print out.

The trick here seems to be with the '0' +
What is this doing? Changing the Year/10 result into a character?

Also, why did you decide to use Year/10 % 10 and not just Year/10 for LogFileChar[6] ? Both yield the correct result.

The trick here seems to be with the '0' +
What is this doing? Changing the Year/10 result into a character?

Correct - the character zero ( '0' ) has the value 0x30, the character one ( '1' ) has the value 0x31 and so on.
Adding, say, 5 to 0x30 give 0x35 aka '5'.

Also, why did you decide to use Year/10 % 10 and not just Year/10 for LogFileChar[6] ? Both yield the correct result.

Only because this year is 11!

feipoa:
Also, why did you decide to use Year/10 % 10 and not just Year/10 for LogFileChar[6] ? Both yield the correct result.

Just so it will work with 4-digit years as well as 2-digit years. I lived through Y2K so I wanted to be ready for Y3K. :slight_smile:

1 Like

That's what I figured. I deleted the extra modulus. Unfortunately, this real-time clock, DS3231, only works up 'til 2099, so it wouldn't matter. Thanks again for your seasoned insight.