This question already has answers here:
What is the lifetime of the result of std::string::c_str()?
(7 answers)
Closed 5 years ago.
Consider the MWE below,
std::string return_string()
{
return "this is a string"
}
int main()
{
const char *y = return_string().c_str();
std::string str = return_string();
const char *x = str.c_str();
std::cout << return_string() << std::endl; //Prints "this is a string"
std::cout << y << std::endl; // Prints Weird characters
std::cout << x << std::endl; //Prints "this is a string"
std::cin.ignore();
return 0;
}
I have a function which returns a string and I need to convert it to a c-style string. Doing return_string().c_str() gives me weird output like
▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌p. But if I store the output of a function in a string first and then convert that string to a c-style string it works. What is wrong with the first way?
When you do return_string().c_str() you get the pointer to a temporary object that will go out of scope once the expression is finished. If you save the pointer and use it later you will have undefined behavior.
With
std::string str = return_string();
you copy the returned temporary object. Getting a pointer to the copy will work since it still exists in the program at the point when you use the pointer.
const char *y = return_string().c_str();
is a problem if you wish to use y later to access the contents. In that line, the return value of return_string() is a temporary that gets destroyed after that line is executed. Hence, y is dangling pointer.
Accessing the contents of a dangling pointer causes undefined behavior.
When you use
std::string str = return_string();
const char *x = str.c_str();
x is not a dangling pointer as long as str is in scope. Hence,
std::cout << x << std::endl;
is well behaved.
You can't "convert from string to const char*". No such thing exists, because a const char* does not contain characters. It is not a string! It only pointers to some characters somewhere.
In this case, via std::string::c_str(), it points to characters that no longer exist.
Related
I'm having troubles initializing a global variable. My C++ is a bit rusty so I can't remember the reason why my code isn't working.
file.cpp
const char * write_path = &(std::string(getenv("FIFO_PATH")) + "/pythonread_fifo")[0];
int main(int argc, char**argv)
{
std::cout << "printing a string: ";
std::cout << (std::string(getenv("FIFO_PATH")) + "/pythonread_fifo\n");
std::cout << "printing a const char*: ";
std::cout << &(std::string(getenv("FIFO_PATH")) + "/pythonread_fifo")[0] << std::endl;
std::cout << "printing write_path:";
std::cout << write_path;
std::cout << write_path << std::endl;
std::cout << "printing FIFO_PATH:" << std::string(getenv("FIFO_PATH"));
}
As a premise: FIFO_PATH has been correctly added to bashrc, and it works, however, when I launch this program this is the output:
printing a string: /home/Processes/FIFOs/pythonread_fifo
printing a const char*: /home/Processes/FIFOs/pythonread_fifo
printing write_path:
printing FIFO_PATH:/home/Processes/FIFOs
As you can see write_path is completely empty.
What's even stranger to me is that if I define write_path as:
const char * write_path = "/home/Processes/FIFOs/pythonread_fifo";
Then write_path is no longer empty, it's correctly initialized and printed.
How can I solve this? Or at the very least, why is this happening?
EDIT: The issue IS NOT related to write_path being global. I placed the definition inside the main and when I try to print write_path, it's still empty
write_path is initialized as a pointer pointing to the 1st element of a temporary std::string, which will be destroyed immediately after the full expression, left write_path dangled, dereference on it leads to UB.
You can use std::string directly, or use a named std::string, then get the pointer from it.
std::string s = std::string(getenv("FIFO_PATH")) + "/pythonread_fifo";
const char * write_path = &s[0]; // or s.c_str()
On the other hand,
const char * write_path = "/home/mverrocc/dss_cp/dss-cp/Processes/FIFOs/pythonread_fifo";
works fine, the c-style string literal has static storage duration and exists in memory for the life of the program, then write_path is always a valid pointer.
const char * write_path = &(std::string(getenv("FIFO_PATH")) + "/pythonread_fifo")[0];
constructs a temporary std::string, takes the address of it's first character then discards the string, thus deleting the underlying char array. This is UB.
Better just use std::string and use c_str() when you need a const char*
You're creating a temporary std::string object, and get a pointer to its first character. This pointer will become invalid as soon as the expression &(std::string(getenv("FIFO_PATH")) + "/pythonread_fifo")[0] ends, when the temporary object is destructed.
Use a std::string object for write_path as well, define it inside the main function, and use the c_str function of the string when you need a null-terminated string.
I have a const char pointer which I know for sure came from a string. For example:
std::string myString = "Hello World!";
const char* myCstring = myString.c_str();
In my case I know myCstring came from a string, but I no longer have access to that string (I received the const char* from a function call, and I cannot modify the function's argument list).
Given that I know myCstring points to contents of an existing string, is there any way to safely access the pointer of the parent string from which it originated? For example, could I do something like this?
std::string* hackyStringPointer = myCstring - 6; //Along with whatever pointer casting stuff may be needed
My concern is that perhaps the string's contents possibly cannot be guaranteed to be stored in contiguous memory on some or all platforms, etc.
Given that I know myCstring points to contents of an existing string, is there any way to safely access the pointer of the parent string from which it originated?
No, there is no way to obtain a valid std::string* pointer from a const char* pointer to character data that belongs to a std::string.
I received the const char* from a function call, and I cannot modify the function's argument list
Your only option in this situation would be if you can pass a pointer to the std::string itself as the actual const char* pointer, but that will only work if whatever is calling your function does not interpret the const char* in any way (and certainly not as a null-terminated C string), eg:
void doSomething(void (*func)(const char*), const char *data)
{
...
func(data);
...
}
void myFunc(const char *myCstring)
{
std::string* hackyStringPointer = reinterpret_cast<std::string*>(myCstring);
...
}
...
std::string myString = "Hello World!";
doSomething(&myFunc, reinterpret_cast<char*>(&myString));
You cannot convert a const char* that you get from std::string::c_str() to a std::string*. The reason you can't do this is because c_str() returns a pointer to the string data, not the string object itself.
If you are trying to get std::string so you can use it's member functions then what you can do is wrap myCstring in a std::string_view. This is a non-copying wrapper that lets you treat a c-string like it is a std::string. To do that you would need something like
std::string_view sv{myCstring, std::strlen(myCstring)};
// use sv here like it was a std::string
Yes (it seems), although I agree that if I need to do this it's likely a sign that my code needs reworking in general. Nevertheless, the answer seems to be that the string pointer resides 4 words before the const char* which c_str() returns, and I did recover a string* from a const char* belonging to a string.
#include <string>
#include <iostream>
std::string myString = "Hello World!";
const char* myCstring = myString.c_str();
unsigned int strPtrSize = sizeof(std::string*);
unsigned int cStrPtrSize = sizeof(const char*);
long strAddress = reinterpret_cast<std::size_t>(&myString);
long cStrAddress = reinterpret_cast<std::size_t>(myCstring);
long addressDifference = strAddress - cStrAddress;
long estStrAddress = cStrAddress + addressDifference;
std::string* hackyStringPointer = reinterpret_cast<std::string*>(estStrAddress);
cout << "Size of String* " << strPtrSize << ", Size of const char*: " << cStrPtrSize << "\n";
cout << "String Address: " << strAddress << ", C String Address: " << cStrAddress << "\n";
cout << "Address Difference: " << addressDifference << "\n";
cout << "Estimated String Address " << estStrAddress << "\n";
cout << "Hacky String: " << *hackyStringPointer << "\n";
//If any of these asserts trigger on any platform, I may need to re-evaluate my answer
assert(addressDifference == -4);
assert(strPtrSize == cStrPtrSize);
assert(hackyStringPointer == &myString);
The output of this is as follows:
Size of String* 4, Size of const char*: 4
String Address: 15725656, C String Address: 15725660
Address Difference: -4
Estimated String Address: 15725656
Hacky String: Hello World!
It seems to work so far. If someone can show that the address difference between a string and its c_str() can change over time on the same platform, or if all members of a string are not guaranteed to reside in contiguous memory, I'll change my answer to "No."
This reference says
The pointer returned may be invalidated by further calls to other member functions that modify the object.
You say you got the char* from a function call, this means you do not know what happens to the string in the mean time, is that right? If you know that the original string is not changed or deleted (e.g. gets out of scope and thus is destructed) then you can still use the char*.
Your example code however has multiple problems. You want to do this:
std::string* hackyStringPointer = myCstring - 6;
but I think you meant
char* hackyStringPointer = myCstring;
One, you cannot cast the char* to a string* and second you do not want to go BEFORE the start of the char*. The char* points to the first character of the string, you can use it to access the characters up to the trailing 0 character. But you should not go before the first or after the trailing 0 character though, as you do not know what is in that memory or if it even exists.
I need to convert number to string and store it into a const char* but problem is that const char* variable is blank after assignment.
In the following example code I expect to see number output converted to const char*
#include <iostream>
#include <string>
int main()
{
int number = 123;
const char* ptr_num_string = std::to_string(number).c_str();
std::cout << "number to string is: " << ptr_num_string << std::endl;
std::cin.get();
return 0;
}
Output is blank:
number to string is:
How do I convert number into a const char* ?
std::to_string returns a temporary std::string.
The pointer returned by std::string::c_str is invalidated by any non-const operation on the string itself - this is because it basically gives you a pointer to the string's internal buffer.
Destroying a std::string is definitely a non-const operation!
Therefore, you can't expect to take a pointer into the string returned by to_string and ever be able to use that. You need to save a copy of that string in the first place:
int number = 123;
std::string const numAsString = std::to_string(number);
char const* ptrToNumString = numAsString.c_str(); // use this as long as numAsString is alive
What you are doing is called Undefined Behaviour - this means that your program is invalid, and anything could happen. It could crash, it could print out some garbage, it could appear to work normally, it could do a different one of these each time you run your program...
It is not "blank" it points to the buffer of string that went out of scope. So accessing it causes Undefined Behavior. You need to keep string alive:
auto str{std::to_string(number)};
auto ptr_num_string{str.c_str()};
std::cout << "number to string is: " << ptr_num_string << std::endl;
I have a very simple code snippet:
#include <iostream>
using namespace std;
string getString() {
return "test";
}
int main(){
const char* testString = getString().c_str();
cout << "string 1:" << testString << endl;
string dummy[] = {"1","2","0"};
cout << "string 2:" << testString << endl;
return 0;
}
I expect the two couts will print the same output, but the output I got is
string 1:test
string 2:1
Can anyone explain why is this happening? Also, there are two things that I observed:
1) If dummy[] is of int type, then they will print the exact same strings test as expected.
2) If I first assign getString() to a string variable, then change the first line in main to const char* testString = variable.c_str(); then they will cout the same strings as expected.
The behavior is undefined.
const char* testString = getString().c_str();
getString returns a temporary object which is destroyed when the evaluation completes. As the result. testString points at internals of a destroyed object, causing undefined behavior.
In practice, it may happen that the data is still at that address for some time, that's why the first cout gives illusion of correctness.
You set pointer to a temporary object that will be deleted after this declaration
const char* testString = getString().c_str();
So the program has undefined behaviour.
The correct code could look like
const char * getString() {
return "test";
}
int main(){
const char* testString = getString();
//...
because string literals have static storage duration.
When you get a low level character pointer from a string object that manages the memory for that string, the pointer is only good for as long as that specific object is alive.
It's more narrow than that, actually. If you call any non-const members on the string object, it means you can't trust any values you got from previous calls to c_str() to still be good--even if the object destructor has not run.
#include <iostream>
using namespace std;
string getString() {
return "test";
}
int main(){
string testString = getString();
const char * testCstring = testString.c_str();
cout << "string 1:" << testCstring << endl;
string dummy[] = {"1","2","0"};
cout << "string 2:" << testCString << endl;
return 0;
}
That's legal, but do not rely upon the pointer from c_str() after you have made any modifying change to the string you got it from -or- that string having been destroyed.
Also note there's no need to get a char * from a string in order to output it. Start thinking in terms of using string objects and don't go to char * unless you have a good reason.
This question already has answers here:
C++ return string keeps getting junk
(1 answer)
ostream cout and char *
(3 answers)
Closed 8 years ago.
I'm new in c++. I wrote this program.
#include <iostream>
using namespace std;
int main(void) {
int x=24;
char y='A';
char* pchar=&y;
int* pint=&x;
cout <<"pchar= "<<hex<<&pchar<<endl;
cout <<"pint = "<<hex<<&pint<<endl;
cout <<endl;
cout <<"pchar= "<<hex<<pchar<<endl;
cout <<"pint = "<<hex<<pint<<endl;
pchar=NULL;
pint=NULL;
getchar();
return 0;
}
and its result
Can you help me to understand why I can't print the address of variables without &?
I think pchar is already the address of y.
thanks
When you use a char* (like your variable pchar) the string overload of operator<< function is used, and when treating it as a string it will print characters until it find the string terminator character ('\0'). Unfortunately in this case pchar points only to a single character, so you have undefined behavior as the function goes out looking for characters in memory not allocated to you.
To print a pointer you have to cast it to void*:
std::cout << "pchar = " << std::hex << reinterpret_cast<void*>(pchar) << '\n';
It works when you print the address of the variable pchar (when you print &pchar) because then the type of the expression is of type char** which have no direct overload, and instead uses the generic pointer overload (case 7 in this reference).
Operator << treated char* as a string. But you can change your code to following
cout <<"pchar= "<<hex<<(void*)pchar<<endl;
It should work.
I cannot access std code now, but cout implementation should contain something like this
operator << (char* char_ptr)
{
//interpret char * as pointer to null-terminated string
... code to output string
}
So there is impossible to print char* as address without casting to something.
You'll need
cout <<"pchar= "<<hex<<static_cast<void*>(pchar)<<endl;
to print the value of pchar (not its address, that would be the address of the variable pchar, not the address to which it points to).
It behaves like this because std::ostream (cout's type) has an overloaded operator<< which takes a char* and treats it specifically to print out a string.
Change this statement
cout <<"pchar= "<<hex<<pchar<<endl;
to
cout <<"pchar= "<<hex<< ( const void * )pchar<<endl;
The problem is that when you write this way
cout <<"pchar= "<<hex<<pchar<<endl;
the compiler considers pchar as an address of the first element of a string and tries to output this string. There is an overloaded operator << for type char * and it is called in this case.
pchar value is address of y. So if you print pchar it will print address of y. &pchar, it will print address of pchar. Remember pchar also have some address.