A Simpler Way to Convert a String to char*?

Hi all

I am using an Arduino Function that returns a String object.
I need to send that string to another function, which accepts a char Array.

I tried simply sending the String object, in the hope that some implicit conversion will happen,
but none did..

So I wrote this small helper function:

char* ConvertStringToCharArray(String S)
{
  int   ArrayLength  =S.length()+1;    //The +1 is for the 0x00h Terminator
  char  CharArray[ArrayLength];
  S.toCharArray(CharArray,ArrayLength);

  return(CharArray);
}

It works, but I wonder...
is this really needed?

No shorter way already exists for such a basic thing, rather than writing this myself?

Thank you

CharArray goes out of scope as soon as you leave the function. So the returned pointer will point to somewhere in memory where the data was in the past.

The rest of your code might use that memory and corrupt the original data.

I am using an Arduino Function that returns a String object.

Does it have to return a String ?

Incidentally, your function returns a pointer to an array that does not exist once the function ends. If you are determined to use Strings then why not just use the toCharArray() function in your code rather than calling a function that calls it ?

Does this help?

https://docs.arduino.cc/language-reference/en/variables/data-types/stringObject/Functions/c_str/
As has been pointed out, the string would have to be global.

sterretje:
CharArray goes out of scope as soon as you leave the function. So the returned pointer will point to somewhere in memory where the data was in the past.

The rest of your code might use that memory and corrupt the original data.

Indeed that's what happened..

I received a partial string, with some garbage after it..
So what is the best way to return a string from a Function?
Only the String object, and never a char*/char[]?

UKHeliBob:
Does it have to return a String ?

Well, the Arduino function that I use, that returns a String object, is Serial.readStringUntil(),
and it only returns a String.. That's how it was defined..

UKHeliBob:
If you are determined to use Strings then why not just use the toCharArray() function in your code rather than calling a function that calls it ?

Because using .toCharArray() requires several lines of code every time, and not just one,
so to make my code simpler and clearer, and to prevent this code duplication, the idea was to wrap it in a function, and thus not having to write several lines each time I need convert String->char*..

the Arduino function that I use, that returns a String object, is Serial.readStringUntil(),
and it only returns a String.

Nobody is forcing you to use that function. You could get the user input directly into a zero terminated array of chars by writing your own function

Because using .toCharArray() requires several lines of code every time

Really ?

 aString.toCharArray(anArray, aString.length() + 1);

UKHeliBob:
Really ?

aString.toCharArray(anArray, aString.length() + 1);

You missed 2 lines.. :slight_smile:
anArray has to be defined first,
and for that, you need the size of anArray before you create it..

And also, you would agree that

ConvertStringToCharArray(S)

is much more easily readable than

int   ArrayLength  =S.length()+1;    //The +1 is for the 0x00h Terminator
char  CharArray[ArrayLength];
S.toCharArray(CharArray,ArrayLength);

You missed 2 lines.. :slight_smile:
anArray has to be defined first,
and for that, you need the size of anArray before you create it..

Declare the array as a global and make it large enough to hold the largest expected String

Job done

UKHeliBob:
Declare the array as a global and make it large enough to hold the largest expected String

That's an option,
thank you.

6v6gt:
Does this help:

c_str() - Arduino Reference
As has been pointed out, the string would have to be global.

That's another option.. and shorter
I'll use it in cases where the String is not lost before or during the operation

There is also readBytesUntil().

And Robin's updated serial input basics that can be adapted to whatever the source is (serial, ethernet, file etc).

I would like to verify:

If I am calling a function that only returns a String object,
and then I have to call a function that only accepts a char*,
there's no better and more streamlined way to take the returned value from the first function, and send it to the second?

I must do the conversion myself?

(this might sound small for you, when it's happening just once, but if you have a long code, messing with strings, and the functions sometimes return String, and sometimes accept char*, this really adds a lot of lines of code....)

So what is the best way to return a string from a Function?
Only the String object, and never a char*/char[]?

No actually this is just as good

void setup() {
  Serial.begin(115200);
  char cstring[30];
  char * cptr = &cstring[0];
  String Str = "Hi There !";
  FillCstring(cptr, Str);
  Serial.println(cstring);
}

void loop() {}

void FillCstring( char * &cstr, String TheString) {
 TheString.toCharArray(cstr, TheString.length()+1);
}

and you could of course do the .readStringUntil() within the FillCstring function and include a maximum size to the cstr (or TheString.length()+1) , actually you really should, but now you can declare the charArray locally and fill it. And not have the memory possibly fragmented.

Sigh..

BTW..
Another thing..

If I need to create a function that gets a Byte array (the function just reads from it, it doesn't write to it)
Must the function have 2 parameters?
function(byte* ByteArray, ArrayLength)

Can't it have 1 parameter
function(byte* ByteArray)
and inside the function, sizeof(ByteArray) will help to get the Length?

If not,
when can sizeof(SomeArray) help us, and when can't it?

sizeof() in the function will return the size of the pointer, not of the array.

It depends what is in that byte array. If it's non-text, you have to specify the length. If it's text, you can use strlen(). But in that case it's better to use a char array.

I see..

So when are the times where sizeof(SomeByteArray) will work?
Only if the Byte Array was defined in the same scope of the call to sizeof()?

Does it matter if the byte array was defined like this:
byte[5] ByteArray;
or like this with malloc()?

Yes

malloc() returns a pointer so you will encounter the same problem.

I correct myself it should be more like this

void setup() {
  Serial.begin(115200);
  char cstring[30];
  ReadCstring(cstring);
  Serial.println(cstring, 30);
}

void loop() {}

void ReadCstring( char * buf, uint8_t bffersize) {
 String TheString = "Hi There"; // or Serial.readStringUntil();
 uint8_t len = TheString.length()+1;
 if (len<buffersize) siz=len;
 TheString.toCharArray(buf, buffersize);
}

Like this it can be 1 line in your code as long as you have a buffer declared.

sterretje:
2)
malloc() returns a pointer so you will encounter the same problem.

Not quite. malloc() does allocate the specified amount of memory (if it can) and returns a pointer to it. However, that memory remains in existence and valid to use even after the function that called malloc() returns. So, as long as you save the pointer's value, you can use the memory.

However, I don't recommend @card5 use this technique. You can quickly get in trouble with it if you don't know what you're doing. Repeatedly calling a function that calls malloc() will quickly lead to grief unless the memory is properly de-allocated when no longer needed. Even then, the order of the allocation / de-allocation sequence will probably be important on a limited-memory platform.