What happens when converting char * to string *? - c++

char * ss = "abscd";
string * b = (string *) ss;
std::cout << ss << std::endl;
std::cout << *b << std::endl;
The output is:
abscd
//empty line
I thought it would be :
abscd
abscd

You must have misunderstood something. First of all you miss a const here:
const char * ss = "abscd";
Next, std::string is meant to replace c-strings, like the one you have with ss. However, std::string is a string, while std::string* is a pointer to a string. As std::string is not related to char as far as conversions between pointers are concerned, your code has undefined behavior.
To create a std::string from a c-string use its constructor, eg like this:
std::string b{ss};
Last but not least, avoid c-style casts like this one string * b = (string *) ss;. You can cast anything to anything without getting a compiler error, but that does not mean that it is correct.

Related

Variable always empty

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.

Can you safely get a pointer to a string from its c_str() const char*?

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.

c++ pass by value segmentation fault

I have a function f() which receives a char* p and gives a const char* to it.
void f(char *p) {
string s = "def";
strcpy(p, s.c_str());
}
In the main() below I expect to get q = "def".
int main(){
char *q = "abc";
f(q);
cout << q << endl;
}
By running this I get segmentation fault and as I am new in C++ I don't understand why.
I also get a segmentation fault when I do not initialize q thus:
int main(){
char *q;
f(q);
cout << q << endl;
}
Knowing that the function's parameter and the way it's called must not change. Is there any work around that I can do inside the function? Any suggestions?
Thanks for your help.
You are trying to change a string literal. Any attemp to change a string literal results in undefined behaviour of the program.
Take into account that string literals have types of constant character arrays. So it would be more correct to write
const char *q = "abc";
From the C++ Standard (2.14.5 String literals)
8 Ordinary string literals and UTF-8 string literals are also referred
to as narrow string literals. A narrow string literal has type
“array of n const char”, where n is the size of the string as
defined below, and has static storage duration
You could write your program the following way
//...
void f(char *p) {
string s = "def";
strcpy(p, s.c_str());
}
//..
main(){
char q[] = "abc";
f(q);
cout << q << endl;
}
If you need to use a pointer then you could write
//...
void f(char *p) {
string s = "def";
strcpy(p, s.c_str());
}
//..
main(){
char *q = new char[4] { 'a', 'b', 'c', '\0' };
f(q);
cout << q << endl;
delete []q;
}
This is an issue that, in reality, should fail at compilation time but for really old legacy reasons they allow it.
"abc" is not not a mutable string and therefore it should be illegal to point a mutable pointer to it.
Really any legacy code that does this should be forced to be fixed, or have some pragma around it that lets it compile or some permissive flag set in the build.
But a long time ago in the old days of C there was no such thing as a const modifier, and literals were stored in char * parameters and programmers had to be careful what they did with them.
The latter construct, where q is not initialised at all is an error because now q could be pointing anywhere, and is unlikely to be pointing to a valid memory place to write the string. It is actually undefined behaviour, for obvious reason - who knows where q is pointing?
The normal construct for such a function like f is to request not only a pointer to a writable buffer but also a maximum available size (capacity). Usually this size includes the null-terminator, sometimes it might not, but either way the function f can then write into it without an issue. It will also often return a status, possibly the number of bytes it wanted to write. This is very common for a "C" interface. (And C interfaces are often used even in C++ for better portability / compatibility with other languages).
To make it work in this instance, you need at least 4 bytes in your buffer.
int main()
{
char q[4];
f(q);
std::cout << q << std::endl;
}
would work.
Inside the function f you can use std::string::copy to copy into the buffer. Let's modify f.
(We assume this is a prototype and in reality you have a meaningful name and it returns something more meaningful that you retrieve off somewhere).
size_t f( char * buf, size_t capacity )
{
std::string s = "def";
size_t copied = s.copy( buf, capacity-1 ); // leave a space for the null
buf[copied] = '\0'; // std::string::copy doesn't write this
return s.size() + 1; // the number of bytes you need
}
int main()
{
char q[3];
size_t needed = f( q, 3 );
std::cout << q << " - needed " << needed << " bytes " << std::endl;
}
Output should be:
de needed 4 bytes
In your question you suggested you can change your function but not the way it is called. Well in that case, you actually have only one real solution:
void f( const char * & p )
{
p = "def";
}
Now you can happily do
int main()
{
const char * q;
f( q );
std::cout << q << std::endl;
}
Note that in this solution I am actually moving your pointer to point to something else. This works because it is a static string. You cannot have a local std::string then point it to its c_str(). You can have a std::string whose lifetime remains beyond the scope of your q pointer e.g. stored in a collection somewhere.
Look at the warnings you get while compiling your code (and if you don’t get any, turn up the warning levels or get a better compiler).
You will notice that despite the type declaration, the value of q is not really mutable. The compiler was humoring you because not doing so would break a lot of legacy code.
You can't do that because you assigned a string literal to your char*. And this is memory you can't modify.
With your f, You should do
int main(){
char q[4 /*or more*/];
f(q);
std::cout << q << std::endl;
}
The problem is that you are trying to write on a read-only place in the process address space. As all the string literals are placed in read-only-data. char *q = "abc"; creates a pointer and points towards the read-only section where the string literal is placed. and when you copy using strcpy or memcpy or even try q[1] = 'x' it attempts to write on a space which is write protected.
This was the problem among many other solutions one can be
main(){
char *q = "abc"; \\ the strings are placed at a read-only portion
\\ in the process address space so you can not write that
q = new char[4]; \\ will make q point at space at heap which is writable
f(q);
cout << q << endl;
delete[] q;
}
the initialization of q is unnecessary here. after the second line q gets a space of 4 characters on the heap (3 for chars and one for null char). This would work but there are many other and better solutions to this problem which varies from situation to situation.

How to convert int and std::string to char*? [duplicate]

This question already has answers here:
Easiest way to convert int to string in C++
(30 answers)
Closed 8 years ago.
How to convert int and std::string to char* ?
I'm trying to do this :
int a = 1;
std::string b = "str";
char* x = a + b;
I don't want something like this:
std::stringstream ss;
std::string str2char;
ss << a;
str2char = ss.str() + "str";
std::vector<char> writable(str2char.size() + 1);
std::copy(str2char.begin(), str2char.end(), writable.begin());
x = &writable[0];
How to deal with this, please.
One way would be to use a string stream (include <sstream>), output data of various types into it, and then grab the output as a string or as a const char*, like this:
std::stringstream ss;
int a = 1;
std::string b = "str";
ss << a << b;
std::string res(ss.str());
const char *x = res.c_str();
Demo on ideone.
If you need to convert to char*, not to const char*, make a copy of c_str instead - replace the last line as follows:
char *x = new char[res.size()+1];
strcpy(x, res.c_str());
// Use x here, then...
delete[] x;
Finally, you can use vector instead of a string to get a writable pointer without the need to delete. Note that this approach does not let you return your char* from a function, because its data would be tied to the scope of the vector with its characters. Here is a demo of this approach.
If you are using C++11, std::to_string() is a good option:
int a = 1;
std::string b = "str";
std::string one = std::to_string(a);
std::string one_plus_b = (one + b);
const char * x = one_plus_b.c_str();
And as it was pointed out by other answers, 'x' can only be used inside the local scope.
int and std::string to char*?
Here are a couple one-liners:
char* p = strdup((std::to_string(a) + b).c_str());
...use p...
free(p);
...or, if your system provides it (I don't think it's in the C++ Standard itself)...
char* p = asprintf("%d%s", a, b.c_str());
...use p...
free(p);
Note that these are C library functions, and the memory allocation is malloc/realloc/free-family, which can not be mixed with new/delete (which means the pointer shouldn't be wrapped in a Standard smart pointer, though of course a free-specific or generic scope guard could be used).

why pointer to char behaves differently as compared to pointersof other data types

I have doubts regarding following statments;
int intvalue = 3;
int *pointInt = &intvalue;
char* p = "string";
cout << pointInt << std::endl; // this will give memory location of intvalue which is ok.
cout << p<< std::endl; // why this will give string value rather than memory location of where string is stored?
Because there is an overload of std::ostream& operator<<(std::ostream&, const char*), which assumes the char* is the first element of a null-terminated string and prints out the whole string.
You can have a lot of fun by attempting to stream a char* that is not the first element of a null-terminated string:
#include <iostream>
int main()
{
char c = 'x';
std::cout << &c << std::endl;
}
char* and const char* are most commonly used to point to C-style null-terminated strings. The standard I/O library takes this into account when being passed one of those types to insert from or extract into. The functions were simply designed to have this special case based on how common it is to want to print out a C-style string.
To get the pointer value, you can try casting to a different pointer type:
std::cout << static_cast<void*>(p) << std::endl;
keyword operator overloading - simply another method of the iostream instance std::cout is responsible for chars and handles that differently. The exact implementation could also yield "Hello World"
cout << (void *) p << std::endl;
I expect it's because << operator has a specific override for char* argument, to output the string.
This is operator<<() overload for the type of the cout object as first parameter and type char* or const char* as second.
There are many such overloads, and you can write some too.
And the reason for this particular overload is to "print" C-style string (null-terminated array of char)