0

In C++ 98, is this a legitimate method to cast from a string to a char *?

char * n = (char *) someString.c_str();

(In my original wording, the function above was recommended by a senior programmer)

Namely, is it a better method than:

s2 = (char *)alloca(s0.size() + 1);
memcpy(s2, s0.c_str(), s0.size() + 1);

(courtesy of convert string to char*)

If so, why?

Use Case:

I need to use a char*, but I don't need to alter the data after it is in the char*. I'm passing it to a display library.

I'm just looking for a short and sweet answer. Thanks!

Edit: I changed the wording to this question because it got down voted. I hope my rewording makes it a better question. I think the answers were interesting and insightful.

For the record: Anyone interested in this question, should look at all the responses. I could only pick one, but I found them all interesting.

Community
  • 1
  • 1
Fred
  • 11
  • 5
  • 2
    `malloc` in C++ isn't great either. Just use `&someString[0]` in C++11 and ensure the null terminator isn't touched by whatever needs the `char *`. – chris Jul 29 '14 at 23:33
  • 4
    It's not correct because `c_str` returns a pointer to a constant string, i.e. a string you shouldn't modify, that's what the `c` stands for. The same goes for the method mentioned by Chris in his comment above, it's gives you a pointer to a constant string. – Some programmer dude Jul 29 '14 at 23:35
  • 5
    "it's not wrong, as it works..." ... famous last words – M.M Jul 29 '14 at 23:36
  • @Fred you need to specify whether the function being called will modify the string or not (and if so, does it need to make the string longer or shorter) – M.M Jul 29 '14 at 23:38
  • @JoachimPileborg You learn something every day, I always thought it was for C, as in a C (as opposed to C++) style string! – T. Kiley Jul 29 '14 at 23:38
  • you need to use a `const char*`. Your conversion to `(char*)` is a really bad idea and invites to undefined bahavior, as you may end up modifying a constant pointer to `char`. – vsoftco Jul 29 '14 at 23:38
  • stating `char * n = (char *) someString.c_str();` then you can alter the `contents` of `someString` through `n`. Goodbye encapsulation, consequences unknown... – 101010 Jul 29 '14 at 23:38
  • 2
    @JoachimPileborg C++11 requires that `std::string` use a null-terminated buffer internally, and that `c_str()` returns a pointer to that. [Ref](http://stackoverflow.com/a/7554172/1505939) . So chris's method is safe so long as the null terminator is not overwritten. – M.M Jul 29 '14 at 23:41
  • Wow, thanks for the fast replies everyone. I should clarify, the way I was doing it was as such: s2 = (char *)alloca(s0.size() + 1); memcpy(s2, s0.c_str(), s0.size() + 1). And she said this method was wrong, and it would be preferable to do the method I mentioned in my OP. – Fred Jul 29 '14 at 23:49
  • Correct or not is the wrong question to ask. When you have 20+ years experience programming you learn how not to get burned. That line of code is just waiting to start a fire. – brian beuning Jul 29 '14 at 23:52
  • @MattMcNabb As an addendum to your comment about the termination, it should be noted that changing one of the characters in the string (either from the pointer or using the string class []` operator) to the terminator character will not change the length of the string object. – Some programmer dude Jul 29 '14 at 23:54
  • @Fred `alloca` is non-standard whereas there are standard options to do it, so I would side against you on this one! But you really need to clarify whether the function being called may modify the string or not, and if so, in what way. – M.M Jul 29 '14 at 23:56
  • @JoachimPileborg `c` in `c_str()` stands for c in c-string not `const`, or so I have always read it. – JarkkoL Jul 30 '14 at 00:18
  • @JarkkoL Well, I guess it could stand for both. :) – Some programmer dude Jul 30 '14 at 00:20
  • @brianbeuning: which line of code is waiting to start the fire? the casting method or the alloc (or both?) – Fred Jul 30 '14 at 00:24
  • @Fred Many old interfaces are not const-correct so it's fine to cast away constness from the c-string returned by c_str() to be able to pass the string to these functions. I presume that this gtk function you are talking about really doesn't modify the string thus it's fine to do this. If this is the case I'm siding with your senior programmer as your solution is just adding unnecessary complexity & overhead without any benefit ;) – JarkkoL Jul 30 '14 at 00:30
  • @MattMcNabb: thanks. Yeah, there's no modification needed to the string. I appreciate all the feedback. I learned C++ in undergrad, but haven't really used it until recently at work. – Fred Jul 30 '14 at 00:31
  • @JarkkoL: yes, that is the case. it's better if she is right. but this forum is nice because I can get real explanations....not just, "your code sucks, change it to this please." LOL. – Fred Jul 30 '14 at 00:36

4 Answers4

3

string::c_str() returns a const pointer to a null-terminated C-style string that contains the same contents as the original string. In most common implementations, c_str() simply returns a pointer to the string's internal data if it is not empty, but that is not required by the C++ standard.

If you just need to read the content of the string and not modify it, there is no need to allocate a separate buffer, just use c_str() by itself. The returned char* will remain valid as long as the string is not altered, either by the =/+=/[] operator, or the insert() or erase() method, or an iterator, etc.

If you need to modify the string via the char* pointer, then you have to allocate a separate buffer, copy the string content into it, modify it as needed, and then copy the new content back to the string using its own methods.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • 1
    *"...but that is not required by the C++ standard"*. In C++11 and later, `string::c_str()` will always point to the internal buffer, as it *is* required by the standard :-) – Karl Nicoll Jul 29 '14 at 23:57
  • 2
    @KarlNicoll in C++98 I think there were vendors who put out copy-on-write strings – M.M Jul 29 '14 at 23:59
  • got it. so it will work, but from the general consensus it's in general a bad practice. – Fred Jul 29 '14 at 23:59
  • 3
    No, the general consensus is - it depends on the context in which it is being used. In a read-only context, it is perfectly safe. In a writable context, it may not be. – Remy Lebeau Jul 30 '14 at 00:00
0

Your senior programmer is wrong. Casting away const-ness like that at the very least is wrong (no guarantees that it points to the actual memory of the string for example), and yields undefined behavior if the underlying objects happen to be const.

Mark B
  • 95,107
  • 10
  • 109
  • 188
  • In C++11 it is guaranteed to point to the actual memory of the string, which is modifiable. And prior to C++11 it is OK to cast away constness so long as the string elements are not actually modified. – M.M Jul 29 '14 at 23:46
  • Unfortunately, we are still using C++ 99. I tried convincing them we should upgrade to C++ 11, but they don't listen. What I need to do is odd. I'm working with a gtk gchar*. There may be a better way of using gtk, but at the moment, I'm passing my data around as strings. When I need to put it to gtk, I convert it to a char*, and then into a gchar*. So I admit what I'm doing in the first place is strange, and there is probably a better way. – Fred Jul 29 '14 at 23:54
0

The answer here depends on whether you need a mutable string or just to be able to read it.

If all you want to do with your char* is to look at the contents then, as the comments have pointed out, you need to assign it to a const char* (and drop the cast).

Your method works, but if all you need to do is read the string, there is no point in copying it to a new location.

If you need to modify the string, then your copy would be appropriate. However, you need to be aware that changes will not be reflected in the original string.

T. Kiley
  • 2,752
  • 21
  • 30
0

First off, memcpy does not allocate memory. It only copies things from one place to another.

In C++ the idiom, using memcpy is:

std::string my_string = "California Needs Rain!\n";
char * p_text_string = new char [my_string.length() + 1U];
memcpy(p_text_string,
       my_string.c_str(),
       my_string.length());
// Add the nul terminator
p_text_string[my_string.length()] = '\0';

Remember that the memory allocated needs to be 1 more than the length of the string because of the nul, '\0', terminator character that needs to be appended.

The std::string is not required to be nul terminated.

Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154
  • If you like the answer or think it helps, click on the check mark. – Thomas Matthews Jul 30 '14 at 00:31
  • for the record, your answer was useful to me, but it looks like I can only pick one. Since all the answers were insightful, I picked the first one. – Fred Jul 30 '14 at 00:48