Helpers.h File for Future Projects

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.

char* StringTochars(String str) {
  char arr[50];
  char* retStr = &arr[0];
  str.toCharArray(retStr, str.length() + 1);
  return retStr;
}

To test this I used:

String JP = "--------START SETUP-------";
char *test = StringTochars(JP);
Serial.print("TESTING HELPERS CHAR*. TEST = ");
Serial.println(test);

The sketch compiles OK but in the serial monitor I get this as a result:-

TESTING HELPERS CHAR*. TEST = 

It’s been a really long day in work and it’s time for bed. I’m really tired and I’m probably missing something really basic :frowning: .

Any help would be appreciated.

Thanks in advance.

When a function exits, its local variables are released from memory, so a pointer to a local variable within the function cannot be returned.

You can obtain a pointer to a string within a String object using the c_str() method.

So you can as follows:

String JP = "--------START SETUP-------";
Serial.print("TESTING HELPERS CHAR*. TEST = ");
Serial.println(JP.c_str());

See the following page for information on the c_str() method:

https://docs.arduino.cc/language-reference/en/variables/data-types/stringObject/

just to insist on the why :

in this code

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;
}
1 Like

are you familiar with .c_str()

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)

// -----------------------------------------------------------------------------
#define MaxTok  10
char *toks [MaxTok];
int   vals [MaxTok];

int
tokenize (
    char       *s,
    const char *sep )
{
    unsigned n = 0;
    toks [n] = strtok (s, sep);
    vals [n] = atoi (toks [n]);

    for (n = 1; (toks [n] = strtok (NULL, sep)); n++)
        vals [n] = atoi (toks [n]);

    return n;
}

Will c_str() not create a constant char array?

c_str() is a method (= member function) of the String class, so it does not construct char array.

The String class allocates memory from the heap memory for a given string using one of the following lines of code:

String str1 = "Hello";
String str2("Hello");

As @J-M-L mentioned in post #3, c_str() returns a pointer to the heap memory for the respective object.

it returns a char * to a char array with the same values as the String variable.

The following document about "String Object constructors" may help you.

https://docs.arduino.cc/built-in-examples/strings/StringConstructor

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.

1 Like

To be precise

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.”

1 Like

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?

The source code for the String class.

There is no contradiction in these answers, while returning const char* or char*, in both cases only a pointer is returned and no array is created.

it is const char* because you can't change the String objects internal character buffer via that pointer.

Ok, I don't argue.
The main idea in my answer was that in any case they doesn't create a new char array.

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

        char *buffer;           // the actual char array
        const char* c_str() const { return buffer; }

Long story short:

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.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.