我有一个非常简单的代码段:
#include <iostream>
using namespace std;
string getString() {
return "test";
}
int main(){
const char* testString = getString().c_str();
cout << "string 1:" << testString << endl;
string dummy[] = {"1","2","0"};
cout << "string 2:" << testString << endl;
return 0;
}
我希望两个couts会打印相同的输出,但我得到的输出是
string 1:test
string 2:1
任何人都可以解释为什么会这样吗?此外,我观察到两件事:
1)如果dummy[]
属于int
类型,那么他们将按预期打印完全相同的字符串test
。
2)如果我首先将getString()
分配给字符串变量,然后将main中的第一行更改为const char* testString = variable.c_str();
,那么它们将按预期输出相同的字符串。
答案 0 :(得分:4)
行为未定义。
const char* testString = getString().c_str();
getString
返回一个临时对象,在评估完成时将其销毁。作为结果。 testString
指向被破坏对象的内部,导致未定义的行为。
在实践中,可能会发生数据仍然在该地址一段时间,这就是为什么第一个cout
给出了正确性的错觉。
答案 1 :(得分:1)
您可以将指针设置为在此声明后将被删除的临时对象
const char* testString = getString().c_str();
因此该程序具有未定义的行为。
正确的代码可能看起来像
const char * getString() {
return "test";
}
int main(){
const char* testString = getString();
//...
因为字符串文字具有静态存储持续时间。
答案 2 :(得分:0)
当你从管理该字符串内存的字符串对象中获取一个低级别字符指针时,指针只有在特定对象处于活动状态时才有效。
实际上,它比那更狭隘。如果你在字符串对象上调用任何非const成员,这意味着你不能信任从先前调用c_str()
得到的任何值仍然是好的 - 即使对象析构函数没有运行。
#include <iostream>
using namespace std;
string getString() {
return "test";
}
int main(){
string testString = getString();
const char * testCstring = testString.c_str();
cout << "string 1:" << testCstring << endl;
string dummy[] = {"1","2","0"};
cout << "string 2:" << testCString << endl;
return 0;
}
这是合法的,但是在你对从字符串中删除它的字符串进行任何修改后,不要依赖c_str()的指针。
另请注意,无需从字符串中获取char *以输出它。开始考虑使用字符串对象,除非你有充分的理由,否则不要去char *。