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

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.

Related

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.

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.

c++ shared_ptr from char* to void*

I am trying to pass a char * string to a function which will execute inside a thread. The function has the following prototype:
void f(void *ptr);
The thread allocation is made by a function similar to the following:
void append_task(std::function<void(void *)> &f, void *data);
I want to allocate a string that will be used inside the thread. Right Now I have this:
string name = "random string";
char *str = new char[name.length()];
strcpy(str, name.c_str());
append_task(f, static_cast<void *>(str));
I would like to discard the obligation to allocate and deallocate memory manually . How can I do this with std::shared_ptr (namely, the cast to void, and do I guarantee that the string is deallocated when the thread ends?)
P.S. Changing the append_task() function IS an option.
First, ditch the second argument to append_task, and make it take a function with no arguments. Then pass the function by value, not reference. That way, you can just bind the extra data within a lambda, and count on std::string and std::function to do the memory management.
Like so:
void f(void *ptr);
void append_task(std::function<void()> f);
int main()
{
std::string name = "random string";
append_task( [=]{f((void*)name.c_str());} );
}
Firstly there is a dangerous bug in your code:
char *str = new char[name.length()];
strcpy(str, name.c_str());
std::string::length returns the size of the string in bytes excluding the null byte at the end of the string. Then you copy into this buffer with strcpy which reads from a const char * until it hits a null byte into your buffer which is now too short to contain the null byte. You then pass this const char * into a function which now has no idea how long this array is and is probably assuming it to be a null terminated array. This kind of mistake is so common in C that you really need to avoid directly handling C-style strings as much as humanly possible.
As to how to solve your problem I can't improve on the solution using lambdas that Sneftel provides.

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]);

C++ char * to string [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
how to copy char * into a string and vice-versa
I have to pass a value into a method that required a char *
MyMethod(char * parameter)
{
// code
}
However, the parameter I need to feed it is currently a std::string. How do I convert the std::string to a char *?
std::string myStringParameter = //whatever
char * myCharParameter = //Convert here somehow
MyMethod(myCharParameter);
You are looking for the c_str() method:
char * myCharParameter = myStringParameter.c_str();
You might need to const_cast the return to get it into a char * instead of a const char *. Refrain from modifying the string though; it is the internal buffer of the std::string object. If you actually need to modify the string, you should use strncpy to copy it to another buffer:
char * myCharParameter = new char[myStringParameter.length() + 1];
strncpy(myCharParameter, myStringParameter.c_str(), myStringParameter.length() + 1);
// And later...
myStringParameter.assign(myCharParameter);
delete [] myCharParameter;
It depends on whether MyMethod actually changes the string that's passed in.
If the only thing you know about it is the signature, then you have to assume it could change the string, and copy it into a temporary buffer per #jdmichal's answer.
It's also possible that the developer of this API didn't know or care about const correctness. So the function takes in a non-const buffer even though it doesn't change it.
If that's the case you can get by with:
MyMethod(const_cast<char*>(myStringParameter.c_str());
In my career I have come across more than a few API's taking in non-const strings that should have been const.
If the function is actually going to modify the string, you'd better create a separate copy:
std::string str = // ...
char* cstr = strdup(str.c_str());
MyMethod(cstr);
// If you want to preserve the changes made:
// str = cstr;
free(cstr);