string to char* function - c++

Quite new to c / c++. I have a question about the below code:
char* string2char(String command){
if (command.length() != 0) {
char *p = const_cast<char*>(command.c_str());
return p;
}
}
void setup() {}
void loop() {
String string1 = "Bob";
char *string1Char = string2char(string1);
String string2 = "Ross";
char *string2Char = string2char(string2);
Serial.println(string1Char);
Serial.println(string2Char);
}
This basically outputs repeatedly:
Ross
Ross
I understand I'm failing to grasp the concept of how pointers are working here - would someone be able to explain it? And how would I alter this so that it could show:
Bob
Ross

This function :
char* string2char(String command){
if (command.length() != 0) {
char *p = const_cast<char*>(command.c_str());
return p;
}
}
Does not make much sense, it takes string by value and returns pointer to its internal buffer, with cased away constnes(don't do it). You are getting some odd behaviour as you are returning values of object that already was destroyed, pass it by ref. Also I'm curious why you need to do all this stuff, can't you just pass:
Serial.println(string1.c_str());
Serial.println(string2.c_str());

As noted by Mark Ransom in the comments, when you pass the string by value, the string command is a local copy of the original string. Therefore you can't return a pointer to its c_str(), because that one points at the local copy, which will go out of scope when the function is done. So you get the same bug as described here: How to access a local variable from a different function using pointers?
A possible solution is to rewrite the function like this:
const char* string2char(const String& command){
return command.c_str();
}
Now the string is passed by reference so that c_str() refers to the same string object as the one in the caller (string1). I also took the libery to fix const-correctness at the same time.
Please note that you cannot modify the string by the pointer returned by c_str()! So it is very important to keep this const.

The problem here is that you've passed String command to the function by value, which makes a copy of whatever String you passed to the function. So, when you call const_cast<char*>(command.c_str()); you're making a pointer to the c string of that copied String. Since the String you've cast is within the scope of the function, the memory is freed when the function returns and the pointer is essentially invalid. What you want to do is change the argument to String & command which will pass a reference to the string, whose memory won't be freed when the function returns.

Your issue revolves around your argument.
char* string2char(String command){
// create a new string that's a copy of the thing you pass in, and call it command
if (command.length() != 0) {
char *p = const_cast<char*>(command.c_str());
// get the const char* that this string contains.
// It's valid only while the string command does; and is invalidated on changing the string.
return p; /// and destroy command - making p invalid
}
}
There are 2 ways to resolve this. The first and most complex, is to pass command in by reference. Thus const String& command and then work with that.
The alternative, which is much simpler, is to completely delete your function; make your char* const char* and just call c_str() on the string; ie
String string1 = "Bob";
const char *string1Char = string1.c_str();

Related

Question related to std::string object and c_str() method in 3 different implementations

I saw a strange behavior the other day.
So I wanted to store lines(present in a vector) in a char array and wanted to use '\n' as delimiter.
I know c_str() method in string class returns a pointer to a char array ending in '\0'.
Based on my experience/understanding of C++.(see greet0 and greet2 functions).
I assumed it should work but it didn't.
Can anyone explain the different behavior in three greet functions? What is the the scope of the object mentioned in each of the greet function?
(also i had a guess that the string object was destroyed in greet1 function but if that would have been the case there should be segmentation fault in cout<<"greet1:"<<w1<<endl; but that does not happen so what exactly is happening in background).
//The snippet that where i first encountered the issue.
const char* concatinated_str(std::vector<std::string> lines, const char *delimiter)
{
std::stringstream buf;
std::copy(lines.begin(), lines.end(), std::ostream_iterator<std::string>(buf, delimiter));
string w = buf.str();
const char *ret = w.c_str();
return ret;
}
//Implementation 0
string greet0(){
string msg = "hello";
return msg;
}
//Implementation 1
const char* greet1(){
string msg = "hello";
cout<<&msg<<endl;
return msg.c_str();
}
//Implementation 2
const char* greet2(){
const char* msg = "hello";
return msg;
}
int main(){
auto w0 = greet0();
cout<<&w0<<endl;
cout<<"greet0:"<<w0<<endl;
auto w1 = greet1();
cout<<"greet1:"<<w1<<endl;
const char* w2 = greet2();
cout<<"greet2:"<<w2<<endl;
}
Output:
0x7fff0ff3e8e0
0x7fff0ff3e8e0
greet0:hello
greet1:
greet2:hello
Returning a std::string or the pointer to a string-literal by value is perfectly fine.
Using the return-value of greet1() though has Undefined Behavior because the std::string whose elements you try to print died at the end of its enclosing function, leaving the returned pointer dangling.
What happens if you dereference a dangling pointer is not defined, acting as if you had a pointer to an empty string due to storage being re-used being one of the more benign possibilities.
As an aside, the address of a std::string is rarely that interesting to someone executing your program, though printing it is perfectly fine.
In statements cout<<&w0<<endl; cout<<&msg<<endl; you're outputting a pointer to std::string. Remove the & to actually print string, not its address. IF you're mystified by same result for two different objects, that might be because of they are addresses of local variables. The memory could be reused as those objects are limited in their lifetime not necessary have unique locations.
In greet0 technically msg is a local variable and stops existing on exit from function but compiler may optimize returned value and instead of copying msg to outside, the actual code would form a proper object at destination w0. With newer compilers Returned Value Optimization is guaranteed.
In function
const char* greet1(){
string msg = "hello";
cout<<&msg<<endl;
return msg.c_str();
}
msg here is a function-local variable, so it represents an object that stops existing at end of scope containing it, i.e. after function had returned. After return line the pointer taken from c_str() is dangling, because that method returns a pointer to the internal storage of std::string. The storage of msg was destroyed and you're invoking Undefined Behaviour by accessing it. Segmentation fault (which is purely Linux event by the way, mechanics in Windows are different) is possible outcome but not necessary.
In third function
const char* greet2(){
const char* msg = "hello";
return msg;
}
msg points to a array containing the constant string "hello". Constant strings created by string literals have same lifespan as a global static object. Those strings are formed during compilation. Exiting function doesn't invalidate the pointer, you still can dereference it because string still exists.
The only code that invokes undefined behavior is related to this function
#Implementation 1
const char* greet1(){
string msg = "hello";
cout<<&msg<<endl;
return msg.c_str();
}
The local object msg of the type std::string will not be alive after exiting the function. It will be destroyed. So the function returns an invalid pointer.
In this function implementation
#Implementation 2
const char* greet2(){
const char* msg = "hello";
return msg;
}
there is returned a pointer to the first character of the string literal "hello" that has static storage duration. It means that the string literal will be alive after exiting the function. Thus the function returns a valid pointer.
This function
#Implementation 0
string greet0(){
string msg = "hello";
return msg;
}
returns a temporary object of the type std::string that is moved (possibly with the move elision) to the variable w0 in main
auto w0 = greet0();
So this function is correct.

How does the '->' operator work and is it a good implementation to modify a large string?

I want to begin with saying that I have worked with pointers before and I assumed I understood how they worked. As in,
int x = 5;
int *y = &x;
*y = 3;
std::cout << x; // Would output 3
But then I wanted to make a method which modifies a rather large string and I believe therefore it would be better to pass a reference to the string in order to avoid passing the entire string back and fourth. So I pass my string to myFunc() and I do the same thing as I did with the numbers above. Which means I can modify *str as I do in the code below. But in order to use methods for String I need to use the -> operator.
#include <iostream>
#include <string>
int myFunc(std::string *str) { // Retrieve the address to which str will point to.
*str = "String from myFunc"; // This is how I would normally change the value of myString
str->replace(0, 1, "s"); // Replacing index 0 with a lowercase s.
return 0;
}
int main() {
std::string myString << "String from main";
myFunc(&myString); // Pass address of myString to myFunc()
}
My questions are:
Since str in myFunc is an address, why can an address use an
operator such as -> and how does it work? Is it as simple as the
object at the address str's method is used? str->replace(); // str->myString.replace()?
Is this a good implementation of modifying a large string or would it better to pass the string to the method and return the string when its modified??
ptr->x is identical to (*ptr).x unless -> is overridden for a type you're dereferencing. On normal pointers, that works as you'd expect it to.
As for implementation, profile it when you implement it. You can't know what compiler will do with this once you turn optimizations on. For example, if given function gets inlined, you won't even have any extra indirection in the first place and it won't matter which way you do it. As long as you don't allocate a new string, differences should generally be negligible.
str is a pointer to std::string object. The arrow operator, ->, is used to dereference the pointer and then access its member. Alternatively, you can also write (*str).replace(0,1,"s"); here, * dereferences the pointer and then . access the member function replace().
Pointers are often confusing; it is better to use references when possible.
void myFunc(std::string &str) { // Retrieve the address to which str will point to.
str = "String from myFunc"; // This is how I would normally change the value of myString
str.replace(0, 1, "s"); // Replacing index 0 with a lowercase s.
}
int main() {
std::string myString = "String from main";
myFunc(myString); // Pass address of myString to myFunc()
}
Is this a good implementation of modifying a large string or would it better to pass the string to the method and return the string when its modified??
If you don't want to change the original string then create a new string and return it.
If it's ok for your application to modify the original string then do it. Also you can return a reference to a modified string if you need to chain function calls.
std::string& myFunc(std::string &str) { // Retrieve the address to which str will point to.
str = "String from myFunc"; // This is how I would normally change the value of myString
return str.replace(0, 1, "s"); // Replacing index 0 with a lowercase s.
}

Convert to std::string and get const char * in one line

I have a number that I need to convert to a const char * (an API I'm using them requires const char * as input to many of its functions). The following works:
int num = 5;
std::string s = std::to_string(5);
const char * p = s.c_str();
as suggested by answers like those in how to convert from int to char*?, but it involves creating the seemingly unnecessary variable s, so I tried the following, but it doesn't work (p points to an empty string afterwards):
int num = 5;
const char * p = std::to_string(num).c_str();
Is there a clean way I can accomplish this? Why doesn't the second example work? The behavior is very similar to what happens if I made this obvious mistake:
const char * p;
{
std::string tempStr( "hi" );
p = tempStr.c_str( );
// p points to "hi" string.
}
// now p points to "" string.
Which makes me suspect that the issue std::to_string(num) immediately goes out of scope or something similar because it's not used to directly initialize anything.
std::string encapsulates managing dynamic memory (created with new[] and delete[]). Let's break it down.
const char * p = std::to_string(num).c_str();
Create a std::string (with a human-readable representation of num).
Get the new[]ly allocated const char* to the string.
Assign that value to p.
Destroy the std::string → delete[] the allocated const char*.
p points to... deallocated data
If you are using a pointer, the data that the pointer points to must exist throughout the lifetime of that pointer.
So, no, there is no way around this other than new[]ing a copy of the string, which you will have to explicitly delete[] later. And at that point, you've thrown the baby out with the bath and have no need to use std::string.
Create a string that lives at least as long as you want to refer to its internal data.
Just use std::string it does everything you want and everything that you would have to do manually if you don't use it.
When you need to pass a const char* to a const char* function simply use std::string::c_str() like this:
some_api_function(mystring.c_str()); // passes a const char*
What you need is a function which returns a char* which holds your value and can be used to manage its lifetime. The problematic version is broken because the char* points to memory which it does not manage.
For example:
std::unique_ptr<char[]> str(int32_t x)
{
std::unique_ptr<char[]> res(new char[12]);
snprintf(res.get(), 12, "%d", x);
return res;
}
Usestd::string everywhere and don't use const char* when not nessecary. They are basically the same thing. I use const char* only when I'm using a file-path.
Use std::string everywhere and your program should work.

The value of c-strings change when I call an unrelated method

I am working on a header file that defines a namespace in which some c-strings are defined.
namespace env {
const char* C_NAME;
const char* SYS_DRIVE;
const char* PROCESSOR;
const char* PROCESSOR_ARCHITECTURE;
const char* OSNAME;
}
My main function looks like this:
int main(int argc, char* argv[], char* env[]) {
initialize_environment_vars(env);
cout << "C_NAME\t\t\t" << env::C_NAME << endl;
/*...*/
return 0;
}
My problem is that the strings I initialize in initialize_environment_vars() do not have the values I want them to have.
void initialize_environment_vars(char* env[]) {
int id = PRIVATE::findEntry(env, "COMPUTERNAME");
env::C_NAME = (str::getAfter(env[id], "=")).c_str(); // getAfter() returns a string
//std::cout << env::C_NAME << std::endl; //Right value!!!
id = PRIVATE::findEntry(env, "SystemDrive");
std::cout << env::C_NAME; //Value at env[id]
/*Here the other constants are initialized in the same way.*/
}
I have found out that in the function initialize_environment_vars() the variables have the right value until I call the function findEntry() to look for another entry.
int PRIVATE::findEntry(const char* const arr[], std::string toFind) {
bool found = false;
int i = 0;
std::string actual;
while(arr[i] && !found) {
actual = arr[i];
if(str::contains(actual, toFind)) {
found = true;
break;
}
i++;
}
if(found)
return i;
else { /*Error message and exit program*/ }
}
After reading this post, string::c_str query, I also thought that my use of .c_str() in initialize_environment_vars() is wrong, because the string that is returned would be destroyed after calling the .c_str(), but this does not seem to be the case, since the env::C_NAME is valid in main().
Thus I have two questions:
Why does my PRIVATE::findEntry(const char* const [], std::string) function change the value of env::C_NAME the way I use it above, even though it only returns an int and does not modify the array nor the entries?
Why is env::C_NAME still valid in 'main()'? Should it not become invalid after the destructor of the string that str::getAfter(const std::string&, std::string) returns is called? (ANSWERED)
Why does my PRIVATE::findEntry(const char* const [], std::string) function change the value of env::C_NAME the way I use it above, even though it only returns an int and does not modify the array nor the entries?
The return value of c_str() is no longer guaranteed to be valid if the string is destroyed or modified.
Why is env::C_NAME still valid in 'main()'? Should it not become invalid after the destructor of the string that str::getAfter(const std::string&, std::string) returns is called?
It's not. It just happens to contain what you want it to contain rather than happening to contain something other than what you want it to contain. If you flip a coin in a circumstance in which it might come up heads, you are doing something broken, but it might happen to work. If you do it again, it might happen not to work. That's why we don't do stuff like this.
Do not confuse how code happens to behave without how you should expect code to behave. In situations where we expect things to be invalid, we have no idea how the code will actually behave. It might happen to do something good, it might happen to do something disastrous. It might change with the compiler options, compiler version, platform, or other parameters.
You have two obvious options. You can change the type of these variables from const char * to std::string or you can use malloc or strdup to allocate memory that will remain valid.
Your "c-strings" in your env environment are just pointers... nothing more. For example, env::C_NAME points to the address that once held the string you got with (str::getAfter(env[id], "=")). Who knows what's there now? You could change your "c-strings" in env to be char buffers of fixed size and use strcpy() to copy the content into them (beware of overrunning the end of the buffers though), or you could leave them as pointers and malloc() space for your copies of the strings, then strcpy() the original strings into your malloc()ed buffers, or best option, use std::string and don't worry about the nitty gritty.

Convert std::string to char * alternative

I have done a search in google and been told this is impossible as I can only get a static char * from a string, so I am looking for an alternative.
Here is the situation:
I have a .txt file that contains a list of other .txt files and some numbers, this is done so the program can be added to without recompilation. I use an ifstream to read the filenames into a string.
The function that they are required for is expecting a char * not a string and apparently this conversion is impossible.
I have access to this function but it calls another function with the char * so I think im stuck using a char *.
Does anyone know of a work around or another way of doing this?
In C++, I’d always do the following if a non-const char* is needed:
std::vector<char> buffer(str.length() + 1, '\0');
std::copy(str.begin(), str.end(), buffer.begin());
char* cstr = &buffer[0];
The first line creates a modifiable copy of our string that is guaranteed to reside in a contiguous memory block. The second line gets a pointer to the beginning of this buffer. Notice that the vector is one element bigger than the string to accomodate a null termination.
You can get a const char* to the string using c_str:
std::string str = "foo bar" ;
const char *ptr = str.c_str() ;
If you need just a char* you have to make a copy, e.g. doing:
char *cpy = new char[str.size()+1] ;
strcpy(cpy, str.c_str());
As previous posters have mentioned if the called function does in fact modify the string then you will need to copy it. However for future reference if you are simply dealing with an old c-style function that takes a char* but doesn't actually modfiy the argument, you can const-cast the result of the c_str() call.
void oldFn(char *c) { // doesn't modify c }
std::string tStr("asdf");
oldFn(const_cast< char* >(tStr.c_str());
There is c_str(); if you need a C compatible version of a std::string. See http://www.cppreference.com/wiki/string/basic_string/c_str
It's not static though but const. If your other function requires char* (without const) you can either cast away the constness (WARNING! Make sure the function doesn't modify the string) or create a local copy as codebolt suggested. Don't forget to delete the copy afterwards!
Can't you just pass the string as such to your function that takes a char*:
func(&string[0]);