[C++] std::string and c_str() problem

This topic is 4093 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

hey, i'd to know how could i store a 'c string' into std::string, the c_str() method seems to be read-only. so, is there another way, or will i have to use char*? error:
Quote:
 75 invalid conversion from const void*' to void*' 75 initializing argument 2 of int SDLNet_TCP_Recv(_TCPsocket*, void*, int)'
code:
Quote:
 std::string msg; msg.reserve(MAX_LEN); SDLNet_TCP_Recv(sock,msg.c_str(),MAX_LEN); //(void*)msg.c_str() == NULL

Share on other sites
You cannot modify a string through its c_str member. Pass a char[] buffer to be filled, and then initialize the string with the buffer.

EDIT: alternatively, use a std::vector to store raw bytes. You can use an std::vector as a buffer, since its storage is guaranteed to be contiguous (although you need to initialize it with a correct size, since only reserving memory will not be sufficient).

Share on other sites
I believe you need to do something like this:

string msg;char *tmp = new char [MAX_LEN];SDLNet_TCP_Recv(sock, tmp, MAX_LEN);msg = tmp;delete[] tmp;

Share on other sites
Quote:
 Original post by drakostarI believe you need to do something like this:string msg;char *tmp = new char [MAX_LEN];SDLNet_TCP_Recv(sock, tmp, MAX_LEN);msg = tmp;delete[] tmp;

MAX_LEN is most likely a compile-time constant, so:
char tmp[MAX_LEN];SDLNet_TCP_Recv(sock, tmp, MAX_LEN);std::string msg = tmp;

should do it. Anyway this was exactly what ToohrVyk said.

Share on other sites
Quote:
 Original post by drakostarmsg = tmp;

This is unsafe, because tmp might not be a nul-terminated C-style string. This operation might therefore not terminate, or it might terminate earlier if a nul character is in the middle of the buffer. In practice, this should be:

msg = std::string(tmp,tmp + MAX_SIZE);

std::vector<char> data(MAX_LEN);SDLNet_TCP_Recv(sock,&(data[0]),MAX_LEN); 

Share on other sites
Quote:
 Original post by ToohrVykThis operation might therefore not terminate, or it might terminate earlier if a nul character is in the middle of the buffer. In practice, this should be:msg = std::string(tmp,tmp + MAX_SIZE);To return to my previous std::vector proposition:std::vector data(MAX_LEN);SDLNet_TCP_Recv(sock,&(data[0]),MAX_LEN); 

Yep, the latter suggestion is better. As an example:

std::string a;
a.push_back( 'c' );
a.push_back( 'h' );
a.push_back( '\0' );
a.push_back( 'c' );
a.push_back( 'o' );
a.push_back( 'l' );
a.push_back( 'a' );
a.push_back( 't' );
a.push_back( 'e' );
std::cout << a.size() << std::endl;
std::cout << a.c_str() << std::endl;

procudes

9
ch

(even though it is storing all 9 chars). Can be misleading / unsafe.

Share on other sites
Quote:
 Original post by theSecondthey, i'd to know how could i store a 'c string' into std::string, the c_str() method seems to be read-only.so, is there another way, or will i have to use char*?

Um, we're not talking about something like this, are we?
char[] foo = "Hello world";std::string str(foo);

Or maybe a std::stringstream?

Maybe I'm just not clear on exactly what you want

Share on other sites
A good example of what to watch out for is demonstrated by your friendly neghborhood telnet client. If you type slow enough each keypress is sent through a single char at a time. Try pressing tab or even backspace or arrow keys. Depending on how you parse the data on the receiving end this can cause lot's of problems.

One thing I have done in the past (and still use) in a text based MUD is a receiving buffer that fills up until a newline character is found. Once a newline is found, that portion of the buffer is parsed to find any special characters or escape sequences and interpreted accordingly. The resulting string is pushed onto a queue of command lines to be parsed etc...

Now, if I ever received a '\0' in the middle of a string that would be an error for me since only text should be passed back and forth for me and I drop their connection because something went wrong. I don't know what kind of information you are expecting from the end user but this is something to consider as well.

Take for example the code below:
Uint32 Recv( TCPsocket sock, std::string &buffer ){  Uint32 temp,total;  char data[MAX_LEN];  total = 0;   while( (temp=SDLNet_TCP_Recv(sock,&data,MAX_LEN)) != 0 )  {    buffer += std::string(data,temp);    total += temp;    // if the sender is spamming, possibly continuing from a previous send    if ( buffer.size() >= MAX_BUFFER_SIZE )        // kill the connection and move on  }  return total;}

That will continue to fill buffer until there is nothing left to receive or you go over a pre-determined amount. It is still up to you to parse buffer according to what you are expecting be there NULL's in the middle or not. I can't stress enough though how important it is to pay attention to how much is received and check it against how much you have parsed. This will help you find potential problems that can be very difficult to track down especially once you move on to higher level things that rely on the socket code to be solid.

Share on other sites
Quote:
Original post by ToohrVyk
Quote:
 Original post by drakostarmsg = tmp;

This is unsafe, because tmp might not be a nul-terminated C-style string. This operation might therefore not terminate, or it might terminate earlier if a nul character is in the middle of the buffer. In practice, this should be:

msg = std::string(tmp,tmp + MAX_SIZE);

Or better yet, avoid declaring variables until you know enough to know how to initialize them, and then actually initialize them.

Putting that together with the std::vector suggestion yields:

std::vector<char> data(MAX_LEN);SDLNet_TCP_Recv(sock,&(data[0]),MAX_LEN);// if the data is a "receive buffer" that might not be null-terminated:std::string msg(data.begin(), data.end()); // If the data is instead a "destination string" that will be null-terminated// (seems unlikely from the function name):// std::string msg(&(data[0]));`

Share on other sites
Quote:
 Original post by evillive2That will continue to fill buffer until there is nothing left to receive or you go over a pre-determined amount. It is still up to you to parse buffer according to what you are expecting be there NULL's in the middle or not.

You meant a NUL, not a NULL.

Quote:
 Original post by ZahlmanOr better yet, avoid declaring variables until you know enough to know how to initialize them, and then actually initialize them.

Quoted for emphasis. Although in this particular case, I'd wager the character buffer is, in fact, a real character buffer and not a string, so I wouldn't bother creating the std::string at all.

Share on other sites

This topic is 4093 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Create an account

Register a new account

• Forum Statistics

• Total Topics
628699
• Total Posts
2984277

• 20
• 10
• 13
• 13
• 11