如果字符串超过10个字母,则char *没有任何明显的原因发生变化。为什么?

时间:2015-12-30 09:55:36

标签: c++

在第2步中,我只更改name_C的值。为什么name_B也会发生变化?

以下是代码:

#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;
    };

这里输出:

    (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

使用:

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

name_B不会改变 如果name_B超过10个字母,为什么str_N会发生变化? 有人能帮我理解这种行为吗?

3 个答案:

答案 0 :(得分:4)

只要相应的c_str停留在范围内且未经修改,对std::string的调用返回的指针有效。

除此之外访问它的行为是未定义的。

例如,(str_L + "-car-" + str_M).c_str();正在向您返回匿名临时c_str。分配后它将立即失效。在您的情况下,name_B无效。

另外,请勿丢弃const char* c_str()次的回复。它的const有一个很好的理由:你不应该尝试通过该指针修改字符串内容。

答案 1 :(得分:3)

您正在导致未定义的行为。

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

你从std :: string :: operator +的结果创建一个temoprary字符串,从中提取C字符数组,但是没有人真正捕获临时字符串。

当一个临时没有被const引用捕获时 - 它立即被销毁。字符串析构函数取消分配内部字符数组并使name_B无效。

所以,这是未定义的行为,因为您尝试使用不再有效的内存地址。

答案 2 :(得分:2)

std::string::c_str()返回指向std::string的内部缓冲区的指针,并保证:

  • 指向以NUL结尾的字符串;
  • 范围[c_str(); c_str() + size()]有效。

在您的情况下,name_B指向临时对象name_B = (str_L + "-car-" + str_M).c_str();的内部缓冲区,当您尝试使用它时,将导致未定义的行为。<登记/> 当您对堆栈进行一些修改(定义两个新的std::string)时,您可能会改变name_B指向的堆栈位置(因为临时保留的内存已被释放)。 / p>

如果您真的必须从std::string获取旧式C字符串,请确保:

  • 修改或销毁std::string::c_str()时,不再使用从std::string检索到的指针,
  • 因此您不会从临时电话中呼叫std::string::c_str()