C++ 将常量char*返回到char*,然后更改数据

C++ 将常量char*返回到char*,然后更改数据,c++,pointers,stdstring,C++,Pointers,Stdstring,我对以下代码感到困惑: string _str = "SDFDFSD"; char* pStr = (char*)_str.data(); for (int i = 0; i < iSize; i++) pStr[i] = ::tolower(pStr[i]); string\u str=“SDFDFSD”; char*pStr=(char*)_str.data(); for(int i=0;i X/COD>是类实例,但结果很可能是“未定义行为”。 如果你认为你的代码“有效”,那

我对以下代码感到困惑:

string _str = "SDFDFSD";
char* pStr = (char*)_str.data();
for (int i = 0; i < iSize; i++)
    pStr[i] = ::tolower(pStr[i]);
string\u str=“SDFDFSD”;
char*pStr=(char*)_str.data();
for(int i=0;i
此处
\u str.data()
返回
const char*
。但是我们将它分配给一个
char*
。我的问题是,


\u str.data()
正在返回指向常量数据的指针。如何将其存储在指向数据的指针中?数据是恒定的,对吗?如果我们将它指定给char指针,那么我们可以像在for语句中那样更改它,这对于常量数据来说是不可能的。

不要这样做。在这种情况下可能没问题,但正如
data()
的文档所述:

返回的指针可能会因进一步调用其他指针而无效 修改对象的成员函数

程序不得改变此序列中的任何字符

所以,如果你保持指针在附近,你可能会非常意外地写入无效内存。或者,事实上,破坏了std::string的实现。我几乎可以说这个函数不应该公开

string为此提供了一个非常量
运算符[]

string _str = "SDFDFSD";
for (int i = 0; i < iSize; i++)
    _str[i] = ::tolower(_str[i]);
string\u str=“SDFDFSD”;
for(int i=0;i
字符串总是在堆上分配内存,所以这实际上不是常量数据,它只是标记为so(在方法data()签名中)以防止修改


<>但是在C++中没有什么是不可能的,所以用一个简单的强制转换,虽然不安全,但是现在可以将相同的内存空间当作可修改的。

在C/C++程序中的所有常量(如<代码> SDSDFSD <下面)将被存储在单独的部分<代码> RODATAs/COD>中。当二进制文件在执行期间加载到内存中时,此部分映射为只读

int main()
{
  char* ptr = "SDFDFSD";
  ptr[0]='x'; //segmentation fault!!
  return 0;
}
因此,任何修改该位置数据的尝试都将导致运行时错误,即分段错误


说到上面的问题,当创建字符串并为其分配字符串时,一个内存(用于保存字符串对象的属性
\u str
)。这在堆上,并且没有映射到只读节。成员函数
\u str.data()
指向内存中映射为读/写的位置

返回类型的
const
限定符确保此函数不会意外地传递给字符串操作函数,这些函数需要非const
char*
指针

在当前迭代中,保存字符串对象数据的内存位置本身没有限制;i、 e.它被映射为具有读/写权限。因此,使用另一个非常量指针(即赋值左侧的
pStr[i]
)修改位置不会导致运行时错误,因为内存位置本身没有固有的限制


同样地,也不能保证工作,这只是您观察到的特定于实现的行为(即,它恰好对您工作),不能总是依赖于此。

您永远不必直接更改从
std::string::data()
std::string::c_str()
返回的数据

要创建
std::string的副本,请执行以下操作:

std::string str1 = "test";
std::string str2 = str1; // copy.
更改字符串中的字符:

std::string str1 = "test"
str1[0] = 'T';
“正确”的方法是使用:


您所做的在标准库级别无效(违反了代码> STD::String Engult),但在C++核心语言级别有效。

数据
返回的
字符*
不应写入,因为例如,理论上它可以在具有相同值的不同字符串之间共享(*)

如果要修改字符串,只需使用
std::string::operator[]
,它将通知对象该意图,并将负责为特定实例创建专用缓冲区,以防该字符串最初被共享

从技术上讲,您可以从指针或引用中舍弃常量,但它是否有效取决于特定情况的语义。允许操作的原因是C++的主要理念是程序员不犯错误,知道他们在做什么。例如,从C++语言的观点来看,技术上是合法的,可以做到<代码> MycPy(和X,Hello,5)其中代码> X/COD>是类实例,但结果很可能是“未定义行为”。 如果你认为你的代码“有效”,那是因为你对“有效”的真正含义有错误的理解(提示:“有效”并不意味着有人曾经观察到代码做了看似合理的事情,但在所有情况下都有效)。一个有效的C++实现是免费的,如果你运行这个程序,它会做任何事情:你观察到一些你认为很好的东西并不意味着什么,可能是你看起来不够接近,或者可能是你运气好(不幸的是,实际上),没有崩溃发生。
(*)在现代,std::string的COW(写时复制)实现不受欢迎,因为它们带来了很多问题(例如多线程),而且内存现在便宜得多。仍然
std::string
合同规定不允许更改
data()的返回值所指向的内存。
;如果你做任何事情都可能发生。

< P>你的问题的简单答案是C++中你可以扔掉变量的“const”。p> 但你可能不应该这样做


我所做的是有效的。但我想知道为什么它是有效的?在我看来,这似乎是错误的。谢谢。@Tahlil:你所做的是无效的。在C++中,成功编译不保证有效性;这个标准充满了未定义的行为,它是无效的;这是未定义的行为,可能会停止工作
std::transform(_str.begin(), _str.end(), _str.begin(), ::tolower);