Small String experiment. Any insights what happened here?

Ran this code as an experiment and got the following result:

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  float pi = 3.1415926535;
  String s = String(pi, 3);
  char *p = s.c_str();
  
  Serial.print("p allocated:");
  Serial.println(p);
  Serial.println(s); //string value OK here

  free(p);

  Serial.print("p de-allocated:");
  Serial.println(p);
  Serial.println(s); //string value NOK here. Was 's' deallocated as well??
}

void loop() {
  // put your main code here, to run repeatedly:

}

OUTPUT:
p allocated:3.142
3.142
p de-allocated:
142

I would have expected 's' to remain unchanged... why is it not so?

You spelled "assigned" wrong

Why are you expecting the memory not to be impacted after that ?

You’ve returned to the heap something that was not for your code to play with (c_str() is a const char * and should be left alone) so the bytes are back to the pool of memory that can be used and there is no implicit warranty that nothing will happen to the bytes you freed up.

To answer the question in your code, the c_str inside the String object was deallocated.

This does not allocate memory; it simply points to the c_str in the String object.

So now you free something that should not be freed. Once p (and hence c_str) is freed, you have no control about what is in there.

1 Like

Why did you expected that?
Method c_str() returns a pointer to the data inside String. Any modification the data on the pointer will change the String data.

From the String class c_str() reference page:

Converts the contents of a String as a C-style, null-terminated string. Note that this gives direct access to the internal String buffer and should be used with care. In particular, you should never modify the string through the pointer returned.

C++ at least allows that c_str() returns the address of the first character in the String. Freeing such a pointer can/will free the String as well. Example for such aliasing in C:

char *s = "hello";
char *p = s;
free(p);

From a C++ perspective, after

free(p);

All bets are off.

you are not even sure (unless you read the String class source code) that the pointer you got was the one obtained by malloc/realloc and in any case any further operations which dereference the pointer is undefined behaviour and and thus anything can happen.

https://en.cppreference.com/w/c/memory/free

that alone is a step in the darkness as a string literals are const char * (could be in flash memory in some architecture and not on the heap)

1 Like

My idea as well. But flash and RAM have almost different addressing modes and pointer types in Harvard architecture. So string literals are usually copied into RAM when assigned to a (non-const) pointer.

@sterretje , @J-M-L (and others as well! :wink: ) thank you for your insights

It is clearer to me now what was going in with that code.

I consider this topic closed now.

that's the bet. You'll likely get at least a waring at compile time for platforms where -Wwrite-strings is on (ESP32 for example)

Do these Harvard platforms allow to access any type of memory by the same pointer type? Not very likely.

fair point (not likely at all)

BTW I just tried compiling

char *s = "hello";

void setup() {
  Serial.begin(115200);
  char *p = s;
  free(p);
  Serial.println("Hello, ESP32!");
}

void loop() {}

and I did get the expected

warning: ISO C++ forbids converting a string constant to 'char*' 
 char *s = "hello";
           ^~~~~~~

"warning" means that code is created for that C standard construct.
Is it possible to modify *s or *p? What's the result?

Could try this code:

char *s = "*ello";

void setup() {
  Serial.begin(115200);
  *s = 'H';
  Serial.println(s);
}

void loop() {}

You'll get the warning both on UNO and ESP32 and execution:
➜ "works" on AVR (prints "Hello")
➜ does not on ESP32 (prints "*ello")

that would be my bet

I have no ESP32 for testing :frowning:

me neither, just on my iPhone at the moment :slight_smile:

but may be that's enough to see:

UNO:

ESP32:

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