使用表达式初始化char *不起作用

时间:2017-01-22 06:54:38

标签: c++ string pointers temporary-objects

以下代码产生错误的输出:

string my_string="My_First_Text";
char * my_pointer=(char *)(my_string+"My_Second_Text").c_str();

为什么呢?在我初始化my_pointer时,我认为不需要my_pointer=new char[100]。如果这个假设不正确,为什么呢?

5 个答案:

答案 0 :(得分:6)

请注意my_string+"My_Second_Text"是一个临时std::string,它会在表达式后立即销毁。这意味着my_pointer将立即被悬空,因为它应该指向的char数组随着临时std::string的破坏而被破坏;请注意,返回的char数组属于std::string,它不是独立的。然后,对悬挂指针的依赖将导致UB。

string my_string="My_First_Text";
char * my_pointer=(char *)(my_string+"My_Second_Text").c_str();
// the temporary constructed from my_string+"My_Second_Text" has been destroyed
// my_pointer is dangled now; deference on it is UB

使用命名变量而不是临时变量就可以了。 e.g。

string my_string = "My_First_Text";
my_string += "My_Second_Text";
const char * my_pointer = my_string.c_str();

BTW:std::basic_string::c_str的返回类型是const char*,对它的任何修改都是UB。因此,尝试将其明确转换为char*是危险的。

  

写入通过c_str()访问的字符数组是未定义的行为。

答案 1 :(得分:3)

除了将c_strconst char*)转换为char*之外,这不是一个好主意,“my_pointer”使用临时初始化,并在表达式后被破坏评估。意思,就在最后一个';'之后在你的代码中 这意味着my_pointer指向不再有效的内存,并且会产生意外结果。

答案 2 :(得分:3)

您的代码有未定义的行为。 +运算符返回一个新的临时字符串对象,该对象将在(my_string+"My_Second_Text").c_str()表达式之外被销毁,因此对该字符串的任何引用都将悬挂并通过它们进行访问具有未定义的行为。

c_str()返回一个指向string的内部char数组的const指针。你不能,也不能通过指针操纵string

(my_string+"My_Second_Text")的结果存储在新变量中,或使用append函数将新字符串附加到现有字符串对象。

std::string new_string = my_string + "My_Second_Text";
const char* char_pointer = new_string.c_str();

my_string.append("My_Second_Text");
const char* char_pointer = my_string.c_str();

答案 3 :(得分:3)

(my_string+"My_Second_Text").c_str()是一个时间值,它将被动态创建和销毁,而不会在程序运行时保存在内存中。

指向它将导致未定义的行为,因为未定义指向的内存。使用strcpy或变量赋值而不是临时值将字符串分配到char *

答案 4 :(得分:3)

临时对象会导致模糊的问题。

Bjarne的C ++书中的相关摘录:

void f(string& s1, string& s2, string& s3)
{
  const char∗ cs = (s1+s2).c_str();  // << Code similar to OP's example
  cout << cs;
  if (strlen(cs=(s2+s3).c_str())<8 && cs[0]=='a') {
  // cs used here
  }
}
     

可能你的第一反应是''但不要这样做!'',我同意。   但是,这样的代码确实写了,所以值得知道它是如何编写的   解释。

     

创建一个临时字符串对象来保存s1 + s2。下一个,   从该对象中提取指向C样式字符串的指针。然后 - 在   表达式的结尾 - 临时对象被删除。然而,   c_str()返回的C样式字符串被分配为。{1}}的一部分   临时对象持有s1 + s2,并且不保证该存储   在临时被摧毁之后存在。因此,cs指向   解除分配存储。

     

输出操作cout << cs可能有效   预计,但那将是纯粹的运气。编译器可以检测并发出警告   针对这个问题的许多变种。

作为旁注,请使用C ++中的适当强制转换而不是C样式转换。阅读

When should static_cast, dynamic_cast, const_cast and reinterpret_cast be used?