C++ string to C string - c++

Consider the following piece of code:
void fun (string &str1, string &str2)
{
const char* cstr;
....
if(strlen(cstr = (str1+str2).c_str()) < 15)
{
// here cstr used
}
}
The condition itself works fine, but in the if-condition body cstr contains garbage. Why?

In this expression:
cstr = (str1+str2).c_str()
you are taking a pointer to the temporary string str1 + str2. This temporary dies at the end of the expression, and so you have undefined behaviour when you try to read from cstr inside the if-body.

I'm assuming the string in your C++ code is std::string.
str1 + str2 produces a temporary std::string object. You invoke the c_str() method on it, and you get a C-style string pointer to the data of this temporary std::string object.
When the temporary std::string goes out of scope and is destroyed, the cstr raw C-style pointer is left dangling, pointing to invalid memory.
If you need to work on the concatenated string str1 + str2, I would suggest you safely store it in a non-temporary std::string object, e.g.:
std::string s = str1 + str2;
// Work with s
if (s.length() < 15) {
// Use s here
...
}
Note also that I invoked the std::string::length() method instead of the C function strlen(). You can use the std::string::size() method, as well.
In general, in C++ code, you should use convenient string classes (like std::string), instead of C-style raw string pointers.

Related

Adding Multiple string values

I have this function that gets 3 input(mostly LPCSTR) and combines them together and finally return the value:
template<typename T>
inline T const& LPCombine(T const& lpStr1, T const& lpStr2, T const& lpStr3)
{
std::string str1, str2, str3, Combined;
LPCSTR lpCombiend = "";
str1 = lpStr1;
str2 = lpStr2;
str3 = lpStr3;
Combined = str1 + str2 + str3;
lpCombiend = Combined.c_str();
return lpCombiend;
}
If I print the value of lpCombined in the same function it's correct and strings or numbers are concatenated so well but If I print the returned value from the LPCombine function from another function like the main function the printed value is something weird and unreadable:
╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
What is the problem?
Combined is destroyed on exit from LPCombine function. As result, LPCombine returns pointer to freed memory and you have unexpected behavior. Maybe you need to return std::string from the function (use std::string as input parameters).
When T == LPCSTR, i.e. const char*, your function returns const reference to a raw char pointer.
The main problem is that this pointer points to the memory of a std::string object (Combined) defined inside the function body:
std::string ..., Combined;
...
lpCombiend = Combined.c_str();
return lpCombiend;
(Note that you seem to have a typo, lpCombiend should be lpCombined.)
When the function terminates, the Combined std::string object is destroyed, so the lpCombiend pointer points to garbage.
In particular, using Visual C++ in debug builds, uninitialized memory is marked with 0xCC byte sequences. Note that 0xCC is the ASCII code 204 = ╠(Box drawing character double line vertical and right), which is exactly what you have in your output.
So, you should consider returning a std::string object instead.
I'd also question the declaration and design of your template function. Does it really make sense to have const T& input string parameters? If T is e.g. PCWSTR (const wchar_t*), the str1 = lpStr1; assignment inside your function body won't work, as str1 is a std::string, and you can't create a std::string from a const wchar_t* raw pointer.

How can I convert const char* to string and then back to char*?

I'm just starting c++ and am having difficulty understanding const char*. I'm trying to convert the input in the method to string, and then change the strings to add hyphens where I want and ultimately take that string and convert it back to char* to return. So far when I try this it gives me a bus error 10.
char* getHyphen(const char* input){
string vowels [12] = {"A","E","I","O","U","Y","a","e","i","o","u","y"};
//convert char* to string
string a;
int i = 0;
while(input != '\0'){
a += input[i];
input++;
i++;
}
//convert a string to char*
return NULL;
}
A: The std::string class has a constructor that takes a char const*, so you simply create an instance to do your conversion.
B: Instances of std::string have a c_str() member function that returns a char const* that you can use to convert back to char const*.
auto my_cstr = "Hello"; // A
std::string s(my_cstr); // A
// ... modify 's' ...
auto back_to_cstr = s.c_str(); // B
First of all, you don't need all of that code to construct a std::string from the input. You can just use:
string a(input);
As far as returning a new char*, you can use:
return strdup(a.c_str()); // strdup is a non-standard function but it
// can be easily implemented if necessary.
Make sure to deallocate the returned value.
It will be better to just return a std::string so the users of your function don't have to worry about memory allocation/deallocation.
std::string getHyphen(const char* input){
Don't use char*. Use std::string, like all other here are telling you. This will eliminate all such problems.
However, for the sake of completeness and because you want to understand the background, let's analyse what is going on.
while(input != '\0'){
You probably mean:
while(*input != '\0') {
Your code compares the input pointer itself to \0, i.e. it checks for a null-pointer, which is due to the unfortunate automatic conversion from a \0 char. If you tried to compare with, say, 'x' or 'a', then you would get a compilation error instead of runtime crashes.
You want to dereference the pointer via *input to get to the char pointed to.
a += input[i];
input++;
i++;
This will also not work. You increment the input pointer, yet with [i] you advance even further. For example, if input has been incremented three times, then input[3] will be the 7th character of the original array passed into the function, not the 4th one. This eventually results in undefined behaviour when you leave the bounds of the array. Undefined behaviour can also be the "bus error 10" you mention.
Replace with:
a += *input;
input++;
i++;
(Actually, now that i is not used any longer, you can remove it altogether.)
And let me repeat it once again: Do not use char*. Use std::string.
Change your function declaration from
char* getHyphen(const char* input)
to
auto hyphenated( string const& input )
-> string
and avoid all the problems of conversion to char const* and back.
That said, you can construct a std::string from a char_const* as follows:
string( "Blah" )
and you get back a temporary char const* by using the c_str method.
Do note that the result of c_str is only valid as long as the original string instance exists and is not modified. For example, applying c_str to a local string and returning that result, yields Undefined Behavior and is not a good idea. If you absolutely must return a char* or char const*, allocate an array with new and copy the string data over with strcpy, like this: return strcpy( new char[s.length()+1], s.c_str() ), where the +1 is to accomodate a terminating zero-byte.

Why strtok modifying stl container

In the below code, i am expecting output to be abc#def. But i am getting output as abcdef. It seems strtok is modifying the vector even though i am not directly passing vector to the strtok function. May i know how it is happening inside
std::vector<std::pair<const std::string, int>> x;
std::vector<std::string> z;
int main()
{
char* pch;
x.push_back(std::make_pair("abc#def", 1));
std::string m = x[0].first;
pch = strtok ((char*)(m.c_str()),"#");
while (pch != NULL)
{
z.push_back(pch);
pch =strtok (NULL, "#");
}
cout<<x[0].first<<endl;
return 0;
}
Copied instances of std::string may use the same backing buffer. That is x[0] and m may actually use the same backing buffer.
This is why the c_str() member returns const char * - you are not allowed to modify it.
You are casting away the const by using the C-style cast (char *).
In general, better use C++ casts: static_cast<>/reinterpret_cast<>/dynamic_cast<> and const_cast<> if you really need to strip the const. The latter is only intended to interface old C-code without const qualifiers. You shall not require to use it within normal C++ code.
Instead using of strtok use find_first_of & find_first_not_of methods of string
like this:
using namespace std;
int main () {
string s="abc#def";
string temp = s,res;
while(temp.size()){
size_t st,en;
st = temp.find_first_not_of("#");
en = temp.find_first_of("#",st);
res= temp.substr(st,en);
cout<<res.c_str()<<endl;
temp=(en == string::npos) ? "" : temp.substr(en);
}
return 0;
}
In your implementation, c_str() must be returning a reference to the internal char buffer of the string, without making any copy. From the manpage of glibc strtok:
BUGS
Be cautious when using these functions. If you do use them, note that:
These functions modify their first argument.
so, yes, strtok applied to the pointer returned from c_str() will modify the string buffer.
You should be using std::getline instead of strtok to split string at #:
std::vector<std::pair<const std::string, int>> x;
int main() {
x.push_back(std::make_pair("abc#def", 1));
std::string m = x[0].first;
std::string token;
while(std::getline(m, token, '#')) {
std::cout << token << std::endl;
}
cout<< x[0].first <<endl;
return 0;
}
or, if you really need to use strtok, at least duplicate the buffer returned by c_str() with strdup (and remember to free() it).

Why does c_str() return the same value for two different strings?

Given a simple file loading function,
std::string load_file(const std::string &filename) {
std::ifstream file(filename);
std::string line;
std::stringstream stream;
while (std::getline(file, line)) {
stream << line << "\n";
}
return stream.str();
}
Why does the following print the contents of another_file twice?
const char *some_file = load_file("some_file").c_str();
const char *another_file = load_file("another_file").c_str();
printf("%s", some_file);
printf("%s", another_file);
The code is broken. You are calling c_str() on a temporary object that is immediately destroyed. Which means that the values returned by c_str() are invalid.
You need to make sure that the std::string objects returned survive at least as long as you hold on to the pointer returned by the call to c_str(). For example:
std::string some_file = load_file("some_file");
std::string another_file = load_file("another_file");
printf("%s", some_file.c_str());
printf("%s", another_file.c_str());
In a line like this:
const char *some_file = load_file("some_file").c_str();
load_file() returns a temporary std::string, and then .c_str() is called on this temporary.
When the temporary is alive, the pointer returned by .c_str() points to some meaningful string. But when the temporary "evaporates" (at the semicolon), then that same pointer is pointing to garbage.
The "garbage" may be the same string that the previous call to load_file() returned, so you have the effect that both raw pointers point to the same string.
But this is just a coincidence.
And your code has a bug.
String classes like std::string were invented as a convenient way to simplify the C++ programmer's life instead of using raw C string pointers. So, just use std::strings if you want to safely manage strings in C++.
Consider using .c_str() just at the boundary with C functions (including printf()).
So, you can refactor your code like this:
// load_file() returns a std::string, so just keep using std::string.
// Note that returning std::string is efficient thanks to RVO/NRVO
// and C++11 move semantics.
std::string some_file = load_file("some_file");
// Idem for this:
std::string another_file = load_file("another_file");
// Convert from std::string to raw C string pointers at the C boundary
printf("%s\n", some_file.c_str());
printf("%s\n", another_file.c_str());
Even some code like this would work fine:
printf("%s\n", load_file("some_file").c_str());
printf("%s\n", load_file("another_file").c_str());
In fact, note that in this case, even if you are using a temporary (i.e. the strings returned by load_file() are not copied to named std::string variables), the temporary is valid during the printf() call, so the raw pointer returned by .c_str() points to a valid string while printf() is doing its printing job.

Pass std::string to a function f(**char)

Is it possible to pass the pointer of a std::string to a function which expects a **char? The function expects a **char in order to write a value to it.
Currently I am doing the following:
char *s1;
f(&s1);
std::string s2 = s1;
Is there no shorter way? It is obvious, that s2.c_str() does not work, since it returns const *char.
That's the appropriate way to handle that sort of function. You cannot pass in the std::string directly because, while you can convert it to a C string, it is laid out in memory differently and so the called function would not know where to put its result.
If possible, however, you should rewrite the function so it takes a std::string& or std::string * as an argument.
(Also, make sure you free() or delete[] the C string if appropriate. See the documentation for whatever f() is to determine if you need to do so.)
No, that's not possible. The function overwrites the pointer (s1) itself. You could pass in the data array from the string (&s2[0]) but that would only allow you to overwrite the currently reserved content space, not the pointer.
The function also somehow allocates memory for the string. You may need to clean that up too. If it had worked, how would it have been cleaned up?
You cannot - the string's char buffer is not writeable, and you shouldn't do it. You can always use an intermediate buffer:
const size_t n = s2.size();
char buf[n + 1];
buf[n] = 0;
std::copy(s2.begin(), s2.end(), buf);
f(&buf);
s2.assign(buf, n);
Yes, write a wrapper function/macro then just use it
One way you can pass your string into your function is to have your string
std::string name;
As the data-member of your object. And then, in the f() function create a string like you did, and pass it by reference like you showed
void f( const std::string & parameter_name ) {
name = parameter_name;
}
Now, to copy the string to char * so you can pass it into a function as a char reference:
From this link:
If you want to get a writable copy like str.c_str(), like char *, you can do that with this:
std::string str;
char * writable = new char[str.size() + 1];
std::copy(str.begin(), str.end(), writable);
writable[str.size()] = '\0'; // don't forget the terminating 0
// don't forget to free the string after finished using it
delete[] writable;
the above is not exception safe!
You can then pass the char * writable into your f() function by reference.