简体   繁体   中英

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?

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.

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.

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::string s), 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::string s, 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM