【发布时间】:2013-07-12 11:34:24
【问题描述】:
我在下面的代码中想知道为什么i和j的结果不同。根据我的直觉,b也指向一个值为4的char的地址。为什么i和j的结果不同
char c='4';
const char *b;
int i,j;
i=atoi(string(1,c).c_str());
b=string(1,c).c_str();
j=atoi(b);
cout<<i<<" "<<j<<endl;
【问题讨论】:
我在下面的代码中想知道为什么i和j的结果不同。根据我的直觉,b也指向一个值为4的char的地址。为什么i和j的结果不同
char c='4';
const char *b;
int i,j;
i=atoi(string(1,c).c_str());
b=string(1,c).c_str();
j=atoi(b);
cout<<i<<" "<<j<<endl;
【问题讨论】:
b=string(1,c).c_str();
b 指向一个临时对象,该对象在此语句后被销毁。它实际上有未定义的行为。
将 char 转换为 int 的简单方法是:
int i = c- '0';
【讨论】:
b = string(1,c).c_str();
这会在表达式之后创建一个超出范围的临时 string。问题是c_str() 返回的指针只有在它被调用的字符串存在并且没有调用非常量函数时才有效。
如果你走这种做事路线,你需要确保在调用atoi时原来的string是有效的。
std::string s(1,c);
b = s.c_str();
j = atoi(b);
s.clear(); // b is no longer valid now!
或者:
j = atoi(string(1,c).c_str());
【讨论】:
b=string(1,c).c_str()中,字符串只是一个临时对象所以pinter c_str是无效的。
在某些架构(操作系统、编译器、stl 实现)上,代码按预期生成“4 4”。试试看here。
问题在于代码依赖于未定义的行为,因为它使用了一个已被销毁的对象返回的指针。
当你写作时
b = string(1,c).c_str();
您正在创建一个临时对象并要求它提供一个指向字符数组的指针。您将此指针分配给 b ,然后临时对象(拥有 b 现在指向的内存)被销毁。假设该库是“健全的”,则在字符串销毁期间将释放此类内存。因此通过指针 b 访问内存是未定义的行为。
当然,您不应该依赖未定义的行为,即使它在某些情况下“有效”。
【讨论】: