I'm trying to get back into programming, specifically console games. I'd heard that curses was good for that, so I found a curses tutorial and I'm getting into that. I'm using C++, and naturally I wanted to take advantage of std::string, but functions like getstr()
only accept char*. Is there any way to pass a string as a char*, or am I gonna have to forgo using C++ strings?
views:
150answers:
6Is there any way to pass a std::string to a function that accepts a char* and changes its contents?
You can still use C++ std::string
, but you'll have to copy the contents into a buffer (std::vector<char>
would be good) and copy it back when using functions that expect a writable char*
buffer.
The only C++ containers that can be safely passed to functions expecting modifiable C-style arrays are std::vector
(don't forget to resize()
it or create it big enough from the start) and boost::array
.
This is going to be tricky to manage if the library modifies the contents AND the length arbitrarily. You could try to use an existing C++ wrapper on CURSES. Or this one (kind of old...).
NCURSES has built-in C++ bindings. Not sure what implementation you are on but check for this.
if you want to put string to such function, you can of course use c_str();
getstr(string.c_str());
moreover, std::string contains also const char string::data() which returns a pointer to the first character in the current string (however not null terminated!).
but it impossible to change this string (gotten in one of above ways) in this function.
but you can do this:
change_c-str(char* str, int size);
//...
string str = "foo";
char arr[str.size()+1];
strcpy(arr, str.c_str());
change_c-str(arr, str.size()); //this is valid as long as change_c-str won't put string which is longer than size
and now the real but illegal answer. All std::string implementations I have ever used will quite happily let you hack the string data
char *naughty = const_cast<char*>(myStr.c_str());
naughty[3] = 'f';
this works. You wont be able to change the length though. Note that indexing outside the string will make Really Bad Things happen, But then thats true with char * anyway
As others have said you have to wrap the functions in a copy to and then back from a C-style buffer.This solution using a short life wrapper object does this pretty elegantly:
using namespace std;
class Wrap {
public:
Wrap(string &S,int Length):Buffer(Length),Orig(S)
{ //constructor copies the string to the buffer
copy(Orig.begin(),Orig.end(),&Buffer[0]);
cout<<"Construct\n";
}
~Wrap()
{ //destructor copies the buffer contents back to the string
Orig=&Buffer[0];
cout<<"Destruct\n";
}
operator char*() { return &Buffer[0]; }
vector<char> Buffer;
string &Orig;
};
void Func(char *T) //a typical C-Style function that modifies the string
{
cout<<"Function\n";
*(T+1)='Q';
*(T+2)='Q';
}
int main()
{
string X("Hiya");
Func(Wrap(X,20)); //Call the function with a wrapped string
cout<<X; //output the modified string
}
This code outputs:
Construct
Function
Destruct
HQQa
which demonstrates how and that it works. This doesn't solve the problem that you have to specify the buffer length but it does allow the function called to change the length AND contents of the string (up to the specified buffer size).