c++:结构数组赋值中 const char* 的意外结果
我的代码:
#include <pthread.h>
#include <iostream>
#include <vector>
using namespace std;
typedef struct {
int id;
const char* name;
const char* out;
} thread_info;
int main(int argc, char const *argv[])
{
int err = 0;
std::vector<thread_info> info_vec;
info_vec.resize(10);
for(int i = 0; i < 10; i++) {
//info_vec[i].id = i;
info_vec[i].name = to_string(i).c_str();
}
int count = 10;
for (size_t i = 0; i < count; i++)
{
/* code */
//cout << info_vec[i].id << endl;
cout << info_vec[i].name << endl;
}
}
结果是:
9
9
9
9
9
9
9
9
9
9
要求解释为什么结果不是“1 2 3 4 5 6 7 8 9” 我的代码有什么问题?
要求解释为什么结果不是“1 2 3 4 5 6 7 8 9” 我的代码有什么问题?
ps:如果我用id代替name,它可以打印“1 2 3 4 5 6 7 8 9”
to_string(i)
是临时的,因此内容在info_vec[i].name = to_string(i).c_str();
之后被释放(或其生命周期已结束),即指针是悬挂。
理论上,解引用释放的指针是UB,即任何事情都可能发生。实际上,正如你的编译器选择做的那样(这不是可移植的[^1]),它们都是
9
,因为它们都指向同一个地方;这是因为每个字符串都被分配,然后释放,下一个字符串在同一位置分配,等等。最终的字符串是9
,因此你在这里得到9
。然而,由于最终的字符串也被释放,如果其他内容占用了这块内存,9
也会被覆盖。
您需要做的是制作例如
name
std::string
而不是 const char*
,它将保存内容,因为您将其复制到另一个地方。
[^1]:正如@Chris所说,既然是UB,看起来指向同一个地方的悬空指针可能会得到不同的内容。
o_oTurtle 的答案是正确的,但核心信息必须是内存必须超出循环迭代的范围,以避免未定义的行为。这并不要求结构成员是 std::string
。
for(int i = 0; i < 10; i++) {
string s = to_string(i).c_str();
info_vec[i].name = new char[s.size() + 1];
std::size_t len = s.copy(info_vect[i].name, 0, s.size());
info_vect[i].name[len] = '\0';
}
另请注意,在 C++ 中,您不需要 typedef。
struct thread_info {
int id;
const char* name;
const char* out;
};
如果您的结构将包含指向动态分配内存的原始指针,您可能需要定义一个析构函数(以及可能的构造函数、赋值运算符等)