Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1063
  • Last Modified:

const char* c_str();

Hi,

I want to use const "c_str()" of string class of STL. But it return "const char* " 

Now i want to modifiy return string of c_str();

What all are the way to do so(modifiy return string of c_str()) ?

Thanks
0
palhade
Asked:
palhade
  • 15
  • 14
  • +1
2 Solutions
 
evilrixSenior Software Engineer (Avast)Commented:
>> What all are the way to do so(modifiy return string of c_str()) ?
You can't it's const for a reason. The C++03 standard does NOT make any guarantees regarding the pointer returned by c_str() in terms of whether it is even the actually internal buffer of the string. The internal buffer of a string does not have to be contiguous in memory nor does it need to be null terminated. The safest thing to do is copy the string to a vector<char> and manipulate that using the address of the first item (the C++ does guarantee the internal buffer of a vector will be contiguous). You must NOT; however, call any members non-const member functions of the vector that the buffer represents whilst manipulating the buffer; otherwise it might be invalidated.

As far as I know the new C++0X standard will provide the same internal representation guarantee on string as is currently placed on vector, but since this is not currently guaranteed by the standard compliers do not have to do this (although I don't know of any that doesn't to be honest)
#include <string>
#include <vector>
#include <algorithm>
 
void foo(char * p)
{
	p[0] = 'H';
}
 
int main()
{
	std::string s = "hello mum";
	std::vector<char> v;
 
	std::copy(s.begin(), s.end(), std::back_inserter<std::vector<char> >(v));
 
	char * p = &v[0];
 
	foo(p);
 
	std::copy(v.begin(), v.end(), s.begin());
}

Open in new window

0
 
itsmeandnobodyelseCommented:
>>>> Now i want to modifiy return string of c_str();
If using

        string s = "Hello World";
        char* ps = &s[0];

the ps has a non-const pointer pointing to a memory of probable 12 allocated bytes. If you delete that pointer  the prog will crash after that. If you write beyond the allocated memory it may cause unpredictable behavior.

You better do your changes using the string member functions. Or you copy the string like

   string s = "Hello World";
   char sz[256] = { '0' };
   strcpy(sz, s.c_str());

Now the sz can be used whereever a non-const pointer was needed.
0
 
itsmeandnobodyelseCommented:
>>>> Now i want to modifiy return string of c_str();
If using

        string s = "Hello World";
        char* ps = &s[0];

the ps has a non-const pointer pointing to a memory of probable 12 allocated bytes. If you delete that pointer  the prog will crash after that. If you write beyond the allocated memory it may cause unpredictable behavior.

You better do your changes using the string member functions. Or you copy the string like

   string s = "Hello World";
   char sz[256] = { '0' };
   strcpy(sz, s.c_str());

Now the sz can be used whereever a non-const pointer was needed.
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
evilrixSenior Software Engineer (Avast)Commented:
>> the ps has a non-const pointer pointing to a memory of probable 12 allocated bytes.
This is not guaranteed by the C++ standard to work (see my post above... the internal representation of a string does NOT have to be contiguous in memory so doing this could very well see you writing to invalid memory) and is therefore not wholly safe (especially if the code is to be x-platform). It is for this reason I did not recommend this method (although, like I said in TR1 and C++0x this will be safe).
0
 
itsmeandnobodyelseCommented:
>>>> so doing this could very well see you writing to invalid memory
It would be a one time test to find that out for your compiler (or look in the impementation basic_string) and the behavior won't change within the lifetime of that compiler version.

But evilrix is right. You better use safe methods like copying the string to a sufficiently sized buffer or editing by using the string member functions. It is more comfortable also.
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> It would be a one time test to find that out for your compiler
The internal representation can be anything and change at anytime. Just because the compiler chooses to hold the string in contiguous memory now doesn't mean that premise will continue. Modifications to the string may cause the strings buffer to fragment, for example. In the end the only safe thing to do is to NOT do this until the standard fully supports it.

The standard was written this way specifically to allow compilers to optimize the internal representation. If the compiler thinks holing the string as a linked list is more efficient than a contiguous stream of bytes then it may do so. In fact, the internal representation doesn't even need to be the string -- it could, if it chose, to tokenize it for efficiency and compactness. The point is, the standard makes no guarantees therefore you can make no assumptions.

You might be tempted to cast away constness of the returned c_str() pointer; however, this too would be a mistake. Firstly, the returned buffer doesn't actually have to be what's int he strings internal buffer (just represent it accurately as a string of chars. Secondly, the string could be in read-only memory and to cast away constness and then try to modify it may cause the application to crash.

It is a real pain this is true... but at the time of writing the standard it seemed like a good idea. In hindsight it's probably not but then the standard was written when compilers were inefficient, processors were slow and memory was costly. Mostly this is now not true, hence the proposal to change this in the next standard.
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> std::copy(s.begin(), s.end(), std::back_inserter<std::vector<char> >(v));
Actually, this would be more efficient if you pre-sized the vector and didn't use back_insertion (it'll save on heap allocations). Below I present a more efficient solution :)
#include <string>
#include <vector>
#include <algorithm>
 
void foo(char * p)
{
	p[0] = 'H';
}
 
int main()
{
	std::string s = "hello mum";
	std::vector<char> v(s.size());
 
	std::copy(s.begin(), s.end(), v.begin());
 
	char * p = &v[0];
 
	foo(p);
 
	std::copy(v.begin(), v.end(), s.begin());
}

Open in new window

0
 
itsmeandnobodyelseCommented:
>>>> The internal representation can be anything and change at anytime.
In theory but not in praxis. For one compiler version the STL implementation of std::string will not change. So, if you do have a contiguous internal string now you'll have it tomorrow until you change the compiler version. So, the only chance that it could fail is that already the current compiler version has the option of non-contiguous internal buffers included, e. g. for strings bigger than 256 characters. But actually I don't know one single STL implementation where that was done, so IMO with all the current compiler versions  you were safe (and I would bet on a few next as well).

>>>> Below I present a more efficient solution
I don't think that copying a string to a vector and back solely because the standard guarantees a vector to provide a contiguos array while for a string it  does not - really can be called an 'efficient solution'. It's like to take a sledgehammer to crack a nut.

You better do

     s[0] = 'H';

if you would like to update 1 single char or for replacing you could do like

    s.replace(s.find("Mum"), 3, "Dad");

0
 
evilrixSenior Software Engineer (Avast)Commented:
>> In theory but not in praxis
It's not theory... it's what's guaranteed (or rather not) by the C++03 standard. Anything else is conjecture!

>> For one compiler version the STL implementation of std::string will not change
I agree but you assert a simple test will prove this, and I@m telling you it won't for the reason I give above.

>> So, if you do have a contiguous internal string now you'll have it tomorrow
But, unless your compiler documentation promises this you'll never know; therefore you only have the standard to fall back on.

>> But actually I don't know one single STL implementation where that was done
This assertion can only be correct if you say, "I don't know one single STL implementation where I have witnessed this", although that is still only an observation and does not mean it is true.

>> It's like to take a sledgehammer to crack a nut.
It depends on whether you wish to write standards compliant code or not. Efficiency and save are often diametrically opposed. I didn't write the standard and nei9ther am I disagreeing with you regarding efficiancy, I am merely stating how this should be done to be standards compliant.
0
 
itsmeandnobodyelseCommented:
>>>> therefore you only have the standard to fall back on.
I checked the implementation. So it is a little bit more than 'witnessing'. You also should see that compliancy to standard isn't fulfilled by all STL implementations.

>>>> It depends on whether you wish to write standards compliant code or not.
No, the alternative is to use string functions what I showed.
0
 
itsmeandnobodyelseCommented:
evilrix, I won't argue about that relying on non-standard behavior is a dangerous thing. But I made C++ long before there was a standard and especially string classes is one thing I really have deep insight. That is cause my former programming language was FORTRAN which has a built-in string type which was were mighty and intuitive especially regarding substrings and I never really achieved to have the same full basic functionality in C++ (the main reason was that FORTRAN has no terminating zero char). But indeed, one of my last attempts used to store an array of internal string buffers. But poor basic_string probably never will become a real good string class.
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> I checked the implementation. So it is a little bit more than 'witnessing'
Of your compiler... that doesn't mean it's the same as the askers.

>> You also should see that compliancy to standard isn't fulfilled by all STL implementations.
Of course not but then at least you'd know that since the compilers documentation should state this and state how ti differs.

>> No, the alternative is to use string functions what I showed
Which just copings the string into a fixed size array, which is (a) far more limiting since you'll need to guess the size at compile time (and run the risk of a buffer overrun) and (a) no more efficient in terms of copying the string to another buffer.
0
 
mrjoltcolaCommented:
>>Secondly, the string could be in read-only memory and to cast away constness and then try to modify it may cause the application to crash.

True in reference to "const char *" but probably a stretch in reference to c_str()

I doubt any STL implementation will return references to read-only memory unless the implementation has some sort of fancy string hashing mechanism against a read-only dictionary.

I agree with the rest of your arguments, and I think use of undocumented behaviour in STL defeats the purpose of using STL, or we should remove the S and call it TL.
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> but probably a stretch in reference to c_str()
hence I said "could"... the point being it is not defined and although we can probably assume, that is all we can do.
0
 
itsmeandnobodyelseCommented:
>>>> the alternative is to use string functions what I showed
I meant the basic_string member functions not the strcpy.
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> I meant the basic_string member functions not the strcpy.
Fair enough but this isn't going to be possible if you are calling into legacy code that expects a char * type.
0
 
itsmeandnobodyelseCommented:
>>>> but this isn't going to be possible if you are calling into legacy code that expects a char * type
Yup, but then I prefer

   int siz = max(512, (int)s.size()+1);
   char* psz = new char[siz];
   strcpy(psz, s.c_str());
   legacy_code_expecting_char_ptr(psz, siz);
   delete []psz;

but of course that is a matter of taste.
   
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> but of course that is a matter of taste.
How does that differ from using a vector, except it's not (unlike using a vector) exception safe?
0
 
itsmeandnobodyelseCommented:
>>>>> How does that differ from using a vector
Hmmm. I would say to copy a string I use strcpy if I need a pointer to outcome. I do it that way since 20 years. I never would use std::copy. Not for any real reason but simply that it doesn't come into my mind. No, that is not quite true. In the early 90's, templates were very buggy in most compilers. I had a project where we had build times of hours because of templates and where I had bad times because of that ...  Therefore I am not a fan of templates - though in the meantime used with STL containers - and IMO template functions were not really OOP but a step back into procedural programming ....

If I would know for sure that a string wasn't modified, e. g. in the interface structure for CListCtrl::InsertItem there is a char* member pszText which is non-const char* as a const char* pointer could not been modified by many compilers, I had no scruples and would cast the s.cstr() or use the &s[0]. There are other more important risks when developing application software - what is my main job for nearly 30 years - than that. In my current project STL isn't used - even forbidden - and 99 percent of all C++ code I currently was writing relies on non-standard framework code (no choice). So, I am always surprised when someone states that without standards the world would break. But, no offense intended.
0
 
itsmeandnobodyelseCommented:
>>>> except it's not (unlike using a vector) exception safe?

Hmmm. Beside of the c_str there is nothing in the above code what could throw an exception ... beside of lack of memory of course. But actually I never experienced a memory exception where handling the exception would have given any benefits? Even for a 'Sorry I am dying' message you would need some piece of free memory ...
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> Beside of the c_str there is nothing in the above code what could throw an exception
It's still not exception safe... your example might not be a problem but we're not talking just about your example.
0
 
itsmeandnobodyelseCommented:
>>>> It's still not exception safe...
Can you show sample code where a code that allocates a buffer by 'new' operator was less safe than one where the same buffer was provided by &v[0] ?

Assume the called legacy code would write beyond buffer boundary or even free the buffer allocated? Do you think the code with the vector could better recover from that?
 
0
 
evilrixSenior Software Engineer (Avast)Commented:
What does a buffer overrun have to do with exception safety?
0
 
palhadeAuthor Commented:
Hi,
I tried following code. It is working. Please let me know if it is correct.
   std::string str = "Hello World" ;
   int length = str.length();
   char* arr;
   arr = new char(length);
   arr = (char*)str.c_str();
 
 
Thanks...
0
 
itsmeandnobodyelseCommented:
>>>> arr = (char*)str.c_str();
It is a correct cast but a flaw if later the buffer actually was used for write operations. Then, the operations might cause a crash in case the internal buffer provided by str was freed or renewed or from read-only memory or ... Moreover you allocated memory to arr which wasn't used after cause you assign annother pointer to arr (memory leak).

So change the above code to  

  std::string str = "Hello World" ;
  int length = str.length();
  char* arr;
  arr = new char[length+1];  // use brackets here
  strcpy(arr, str.c_str());
  // use arr
  ...
  delete [] arr;
 


 

0
 
evilrixSenior Software Engineer (Avast)Commented:
>> Please let me know if it is correct.
Well no and further more, as I've already pointed out, the code isn't exception safe. Did you follow the discussion in this thread? Did it make sense? If not, is there anything you need clarifying? Using a vector to do this is simple and completely safe (in terms of it will automatically take care of all memory house-keeping. Is there any reason you'd prefer to go the route that will be less safe?

Can I refer you back to http:#24222845 so you can see just how simple it is to use a vector?
0
 
itsmeandnobodyelseCommented:
>>>> in terms of it will automatically take care of all memory house-keeping
Because of that you can't use it if you pass the pointer to some code which might delete or reallocate the given pointer.

>>>> Is there any reason you'd prefer to go the route that will be less safe?
The above code snippet is as safe as the vector solution. There is no realistic scenario where the above code fails and the vector solution doesn't fail.

A better solution as both is to use string member functions to manipulate the string. That means you should try to omit on the writeable char pointer if possible.
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> Because of that you can't use it if you pass the pointer to some code which might delete or reallocate the given pointer.

This was never a criteria stated.

>> The above code snippet is as safe as the vector solution
As already stated, it is not exception safe. You understand what this means, right?

>> There is no realistic scenario where the above code fails and the vector solution doesn't fail.
You need to write additional code to catch and handle exceptions specifically to do clean-up... this is unnecessary when using a vector. As it stands, the example you give will leak on exception.
0
 
itsmeandnobodyelseCommented:
>>>> As it stands, the example you give will leak on exception.
Probably not. The only reason for an exception is lack of memory hence no memory allocated hence no leak.

Can you tell from the standard what happens if the vector wouldn't be able to allocate the memory requested. Is there any chance to go on when that occurs?

>>>> This was never a criteria stated.
Don't think that exception safety was a criteria stated either.
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> Can you tell from the standard what happens if the vector wouldn't be able to allocate the memory requested
An exception std::bad_alloc will be throw, which can be caught and handled with no extra code to prevent a leak. You assume trying to allocate too much memory has to be fatal... a well written application should be able to handle such an eventuality safely.

>> Don't think that exception safety was a criteria stated either.
Code that is well behaved doesn't need to be stated, it's always a requirement
0
 
itsmeandnobodyelseCommented:
>>>> Code that is well behaved doesn't need to be stated, it's always a requirement

==> using the operator new is not well behaved in C++ as it is not exception safe but must replaced by using std::vector.
0

Featured Post

Upgrade your Question Security!

Add Premium security features to your question to ensure its privacy or anonymity. Learn more about your ability to control Question Security today.

  • 15
  • 14
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now