Hi, I’m creating a Helpers.h file which I can use in future projects and will contain a load of regular conversion functions I can call. One of the functions returns nothing and is confusing me!!! It’s just a simple conversion from string to character array.
the array arr is local to the function. It means its memory is allocated on the stack when the function is called and freed when the function terminates. So returning a pointer to a memory that is no longer valid is a bug. If you are unfamiliar with that idea, it's time to read about scope
The right way to do this in your case is to use indeed the existing String member function c_str() that gives you the pointer to the underlying text.
In general it's a bad idea to have the function you call responsible to provide the memory for something, we tend to prefer that the caller is responsible for this (so that you don't forget also to free that memory when no longer necessary). But that being said, if you really wanted to be returning a valid pointer from the function (and loosing the ability to call that function in a recursive way, or multiple times in a row, or from two cores as they would share the same buffer) then you could allocate the variable inside the function in a permanent way. This is done with the static keyword.
char* StringTochars(String str) {
static char arr[50]; // static means the variable will survive the end of the function
char* retStr = &arr[0];
str.toCharArray(retStr, str.length() + 1);
return retStr;
}
but note that this is error prone if your str is too long, so it would be best to ensure you never overflow. The toCharArray() function second parameter is the size of the destination buffer.
char* StringTochars(String str) {
const size_t maxLen = 50; // max number of meaningful bytes
static char arr[maxLen + 1]; // +1 for the trailing null
str.toCharArray(arr, maxLen + 1);
return arr;
}
here's an example of a function that processed values are allocated in memory for subsequent use
tokenize() breaks a line of text into separate fields with char ptr arrays to each individual fields as well as arrays of ints if the field is numeric. (various levels of encapsulation can be used to avoid the use of global variables)
You shouldn't put function implementations and variable definitions in a .h header file. Doing so will results in "multiple definition" errors if the .h is included in more than one compilation units (source files).
Rather, you should implement proper .h and .cpp files, splitting the declarations from implementations and definitions. For a basic guide, see My Post #5 in this Thread.
In that declaration there are two separate const qualifiers that mean different things.
The first const in const char* means that the function returns a pointer to constant characters ➜ you cannot use the returned pointer to modify the contents of the string.
The second const after the parameter list applies to the member function itself. It means that calling this function does not modify the state of the object.
So together, const char* c_str() const means “a member function that does not modify the object and returns a pointer to read-only characters.”
OK so getting really confused now regarding c_str()….. some people are saying it just creates a char* others saying it creates a const char* and others state it does not construct char array at all. Googling it I still get the same conflicting info. Where can I find a definite answer?
i said it returns a char * but JML provided the correct answer that it returns a const char * which mean i can't be modifed. It doesn't need to construct a char array because String maintains the string as a char array.
From Arduino/hardware/arduino/avr/cores/arduino/WString.h
Your String instance maintains a char buffer with the typical c-string representation internally. This buffer is hidden and you only modify the content through the methods / operators offered by the String class. So internally the buffer is modifiable.
When you call c_str() on a String instance, you get a pointer to this underlying representation and because the class does not want you to mess with the internal buffer it gives you this pointer as a const meaning the compiler won’t let you modify what’s pointed through this pointer.
Passing the internal pointer out somewhat breaks encapsulation so it’s normal for the class to take some precautions but this way there is no need to create an second buffer using precious RAM if you don’t really need a copy as all you need is read only access to the buffer.