trewius
trewius

Reputation: 49

With a string longer than 10 letters, char* changes without any apparent reason. Why?

In step 2 I change only the value of name_C. Why does name_B also change?

Here is the code:

#include <cstdlib>
#include <dirent.h> 
#include <iostream>
#include <fstream>
#include <direct.h>

using namespace std;

int main(int argc, char *argv[])
    {
// step 1
        char *name_A;
        char *name_B;
        char *name_C;

        string str_L = "hello";
        string str_M = "stringVar_A";  ;

        name_A = (char *) str_M.c_str();  
        name_B = (char *) (str_L + "-car-" + str_M).c_str();
        name_C = (char *) str_L.c_str();

        cout << " name_A= " << name_A  << endl;
        cout << " name_B= " << name_B  << endl;
        cout << " name_C= " << name_C  << endl << endl << endl;

// step 2
        string str_N = "myStringMyString"; // (in my real code, i can't put this line in step 1)
        string str_R = "ABCDEFGHI" + str_N;   // (in my real code, i can't put this line in step 1)
        name_C = (char *)str_R.c_str();   // change only name_C

        cout << " name_A= " << name_A  << endl;
        cout << " name_B= " << name_B  << endl; // changed, why?
        cout << " name_C= " << name_C  << endl; // changed, ok.

        system("PAUSE");
        return EXIT_SUCCESS;
    };

Here the output:

    (step 1:)
name_A= stringVar_A
name_B= hello-car-stringVar_A
name_C= hello

    (step 2:)
name_A= stringVar_A
name_B= ABCDEFGHImyStringMyString
name_C= ABCDEFGHImyStringMyString

With:

string str_N = "myString"; // in step 2...  

name_B does not change.
Why does name_B change if str_N is longer than 10 letters?
Can someone help me understand this behavior?

Upvotes: 1

Views: 84

Answers (3)

David Haim
David Haim

Reputation: 26476

You are causing undefined behaviour.

   name_B = (char *) (str_L + "-car-" + str_M).c_str();

you create a temoprary string from the result of std::string::operator + , extract the C-character array out of it, but then no-one really cathes the temporary string.

when a temporary is not caught by const reference - it is destroyed right away. the string destructor de-allocates the inner character array and invalidates name_B.

so, this is undefined behaviour since you try to work with memory address that is no longer valid.

Upvotes: 3

YSC
YSC

Reputation: 40070

std::string::c_str() returns a pointer to an internal buffer of a std::string with the guarantee that:

  • it points to a NUL-terminated string;
  • the range [c_str(); c_str() + size()] is valid.

In your case, name_B points to an internal buffer of a temporary object name_B = (str_L + "-car-" + str_M).c_str(); which will lead to an Undefined Behaviour when you'll try to use it.
When you make some modifications on your stack (you define two new std::strings), you probably alter the stack place where your name_B points to (since the memory reserved by your temporary has been freed).

If you really have to get old style C-strings from your std::strings, make sure:

  • The pointer retrieved from std::string::c_str() is no longer used when the std::string is modified or destroyed,
  • hence you don't call std::string::c_str() from a temporary.

Upvotes: 2

Bathsheba
Bathsheba

Reputation: 234665

The pointer returned by a call to c_str is only valid for as long as the corresponding std::string stays in scope and is unmodified.

The behaviour in accessing it beyond that is undefined.

For example, (str_L + "-car-" + str_M).c_str(); is returning you the c_str of an anonymous temporary. It will be immediately invalid after the assignment. In your case, name_B is invalidated.

Also, don't cast away the const char* return of c_str(). It's const for a very good reason: you should not attempt to modify the string contents through that pointer.

Upvotes: 4

Related Questions