4

I'm using the pdCurses library and am aiming to only really use strings in my C++ console game but the curses mvinstr() function or any insert function requires a non-const char * as a parameter.

  • My solution at first to this problem was simply entering in string.c_str(), but that returns a const char * which apparently doesn't work with the function.
  • Next I put (char *)string.c_str() but this only causes an unhandled exception.
  • Finally I just tried char *test = string.c_str() but that's not compatible with const either.

What do I do to solve this?

K i just tried const_cast() and i still get an exception thrown and break.... I don't know why PDcurses only takes non-const char pointers.... =(

alright making a char* buffer didn't work when i used this code (time_s is the sting):

size_t length; 
    char buffer[12]; 
    length=time_s.copy(buffer,5,0); 
    buffer[length]='\0';
mvinstr(time_loc_y, time_loc_x, buffer);

i even put a stop before mvinstr() and checked the buffer's contents which was "00 /0" EXACTLY WHAT I WANTED.

but i get an access violation point to "xutility"....

Griffin
  • 2,399
  • 7
  • 48
  • 83

7 Answers7

7

mvinstr(x,y,str) and others "take characters (or wide characters) from the current or specified position in the window, and return them as a string in str (or wstr)."

The function will actually modify the string, so you cannot safely cast the const away, especially since c_str specifies that you should not modify the returned string.

You need something along the lines of:

const MAX = 100;
char buf[MAX];
mvinnstr(x, y, buf, MAX);
...error checking...
string s = buf;

Note that I avoided mvinstr in favour of mvinnstr to avoid the potential for buffer overflows.

ikegami
  • 367,544
  • 15
  • 269
  • 518
  • @Griffin, sounds like a buffer overflow, and I specifically showed how you can avoid that. Note: It's not clear whether you should pass MAX or MAX-1 to `mvinnstr`, but that can be determined from testing. – ikegami May 17 '11 at 05:20
3

How about

char* buffer = &str[0];
int fetched_len = mvinnstr(time_loc_y, time_loc_x, buffer, str.size());
str.resize(fetched_len);

In general, though, you should make a writable buffer instead of removing const from a pointer that has it. e.g.

vector<char> charvec(MAX_LENGTH);
str = string(&charvec[0], mvinnstr(time_loc_y, time_loc_x, &charvec[0], charvec.size());
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • C++03 tried to guarantee your first snippet would work (and failed), but it is guaranteed to work in C++0x. In both cases, make sure there's enough reserved memory in the string. – GManNickG May 17 '11 at 00:18
  • @GMan: I was trying to avoid looking up the particular API, in order to provide a more general answer, but I've just edited it to prevent overflow. – Ben Voigt May 17 '11 at 00:21
  • Hmm... just realized this is similar to my answer but with the added `resize` call ... might you want to show what you're doing with the `&str[0]` call more explicitly so that the OP doesn't get lost. +1. – Billy ONeal May 17 '11 at 00:34
  • @Billy: That's what I had in an earlier revision, ... I'll see what I can do to emphasize that. – Ben Voigt May 17 '11 at 12:25
  • @Ben: Awesome -- removed my answer because yours is better. – Billy ONeal May 17 '11 at 12:31
  • 1
    @GMan: [Technically the standard doesn't require it to work, but there are no known implementations where it does not work.](http://stackoverflow.com/questions/2256160/how-bad-is-code-using-stdbasic-stringt-as-a-contiguous-buffer) – Billy ONeal May 17 '11 at 12:32
  • @Billy: Isn't that what I said? – GManNickG May 17 '11 at 17:56
  • @GMan: No -- you said only that C++03 tried to make that the case, but that it didn't. My point is despite the fact that it doesn't, it really doesn't matter. :) – Billy ONeal May 17 '11 at 18:57
  • @Billy: Right, but then I said "make sure the buffer is big enough to pull it off", which implies that it's ok. (Admittedly, reading again I wasn't clear enough about it.) – GManNickG May 17 '11 at 19:06
  • @GMan: Hehe -- wasn't saying you were incorrect -- just wanted to be more explicit about it. (And serve my self serving interest of linking to one of my questions ;) ) – Billy ONeal May 17 '11 at 20:01
2

Cautiously - if the code that uses the was-const data tries to modify it, anything can happen.

In short:

const std::string str = "...";
char *caution = const_cast<char *>(str.c_str());

However, given that you are getting unhandled exceptions, you probably need to make a modifiable copy of the constant string before calling mvinstr(). Maybe:

const std::string str = "...";
char *caution = new char[str.length()+1];
str.copy(caution, str.length()+1);
...call to mvinstr()...
delete[] caution;
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
1

Since mvinstr is actually storing data into the array pointed at by the char*, you can't use a string there. You need to allocate an array of char, pass that to mvinstr, and then transfer the characters to a string if you want.

If you were using a function that could have been declared with a const char * (i.e. it doesn't actually modify the array), then you could use const_cast<> to remove the const.

const_cast<char *>(str.c_str());

But that's not what you're doing here. const_cast might work if you tried it, but it would be by accident, not because it's supposed to work, and a new compiler or library version could break it at any time.

cjm
  • 61,471
  • 9
  • 126
  • 175
1

Try something like the following, then use buffer wherever you need a char*. As Ben mentioned, you need to be very careful to keep the buffer larger than the string plus null terminator.

const int BUFFER_SIZE = 255;

string str ("Your string");
char buffer[BUFFER_SIZE];
if (str.length() < BUFFER_SIZE)
{
    size_t copy_length;
    copy_length=str.copy(buffer,str.length(),0);
    buffer[copy_length]='\0';
}
Chris Frederick
  • 5,482
  • 3
  • 36
  • 44
0

Removing const can be done with const_cast, and is sometimes necessary for using legacy interfaces that were written in C and don't use const. In such cases, you can do:

char* ptr = const_cast<char*> (str.c_str());

However, from the cplusplus reference page on c_str():

The returned array points to an internal location with the required storage space for this sequence of characters plus its terminating null-character, but the values in this array should not be modified in the program and are only granted to remain unchanged until the next call to a non-constant member function of the string object.

This means that it is your responsibility to ensure that ptr is not used to modify the string, and you must handle the lifetime of ptr appropriately. I.e., you cannot continue to use ptr after str is out of scope, or after you call any non-const methods on str. If you do that, you go into Undefined Behavior, and will likely crash.

If you are looking for a safe way to interact with a legacy interface that takes char*, you can make your own writable copy:

char* ptr = new char[ str.size() + 1 ];
strcpy(ptr, str.c_str());
ptr[str.size()] = '\0';
// ... use ptr as much as you want...
delete [] ptr;
Tim
  • 8,912
  • 3
  • 39
  • 57
  • `new []` and `delete []`? Just use `std::vector`. – Ben Voigt May 16 '11 at 23:45
  • @Ben, how is a `vector` supposed to help with using a legacy interface that expects `char*` as an input parameter? A `boost::scoped_array` would work far better here. – Tim May 16 '11 at 23:51
  • 3
    `vector vec = FillMeWithData(); legacy_c_function(&vec[0]);` Not so say `boost::scoped_array` isn't also an option. So long as there's no raw pointers floating around. – Dennis Zickefoose May 17 '11 at 00:08
  • @Dennis: Although, the data comes from the legacy c function. So `vector vec(str.size() + 1); legacy_c_function(&vec[0]);` – Ben Voigt May 17 '11 at 00:14
-1

if (string.empty()) foo(const_cast<char*>(string.c_str());

a better but still evil way to remove const is const_cast(const_string); (its better to find via grep/search)

Witch exception did you encountered? Do u just read the char* or do you change the values? if you change, you should redesign your code.

const char* test = string.c_str(); Does not create a deep copy of string, only a pointer to the internal data representation of string.data().

=> (a suggestion) find a C++ book where you can get a more in deep view of c++. Or something like to C++.

dirk
  • 1