我可以从C++字符串中获取非const C字符串吗?

jer*_*son 25 c c++ string

C++中的const-correctness仍让我感到头疼.在使用一些旧的C代码时,我发现自己需要将C++字符串对象转换为C字符串并将其分配给变量.但是,变量是a char *c_str()返回a const char [].有没有一个很好的方法来解决这个问题,而不必自己动手去做呢?

编辑:我也试图避免调用新的.我很乐意交易稍微复杂的代码,以减少内存泄漏.

sbi*_*sbi 24

因为对于我莫名的原因,没有人回答了这个我现在做的方式,因为其他的问题现在正在封闭指向这一个,在这里我要补充这一点,即使一年即将到来太晚将意味着它挂在最堆的底部......


使用C++ 03时,std::string不保证将其字符存储在连续的内存中,并且结果c_str()不需要指向字符串的内部缓冲区,因此保证工作的唯一方法是:

std::vector<char> buffer(s.begin(), s.end());
foo(&buffer[0], buffer.size());
s.assign(buffer.begin(), buffer.end());
Run Code Online (Sandbox Code Playgroud)

由于没有已知的实现,实际上使用的非连续的内存,由于std::string使用了被许多人认为,如果这是有保证的,规则将被改变为即将到来的标准,现在保证其字符连续内存.所以在C++ 1x中,这应该工作:

foo(&s[0], s.size());
Run Code Online (Sandbox Code Playgroud)

但是,这需要注意:在调用任何可能更改字符串的成员函数之前,&s[0](仅作为s.c_str()BTW的结果)的结果才能保证有效.所以你不应该把这些操作的结果存储在任何地方.正如我的例子所做的那样,最安全的是在完整表达结束时完成它们.

  • 这个 Q/A 真的很老了,虽然恕我直言很好并且投票了。也许,值得一提的是,C++11 发生了变化: _basic_string 的元素是连续存储的,即对于 basic_string s,&amp;*(s.begin() + n) == &amp;*s .begin() + n 对于 [0, s.size()) 中的任何 n,或者等效地,可以将指向 s[0] 的指针传递给期望指向 CharT[] 数组第一个元素的指针的函数._(引用自 [cppreference: std::basic_string](https://en.cppreference.com/w/cpp/string/basic_string)) (2认同)

dmc*_*kee 12

我想总有strcpy.

或者char*在C++代码中必须与旧东西接口的部分使用字符串.

或者重构现有代码以使用C++编译器进行编译然后使用std:string.

  • 如果你正在避免使用new(正如你在另一条评论中所说的那样),你应该考虑使用`strncpy`来避免过度运行你的堆栈或静态分配的缓冲区......但是你也必须处理std :: string另一种方式是缓冲情况. (2认同)

Joe*_*bel 12

你需要在这里做一个重要的区别:char*你希望指定这个"道德常数"吗?就是说,抛弃const- 只是一种技术性,你真的仍然会把字符串视为一个const?在这种情况下,您可以使用强制转换 - 无论是C风格还是C++风格const_cast.只要你(和其他人谁以往任何时候都维持这个代码)有纪律来治疗char*const char*,你会没事的,但是编译器将不再看着你回来,所以如果你把它作为一个非const您可能正在修改代码中其他内容依赖的缓冲区.

如果您char*将被视为非const,并且您打算修改它指向的内容,则必须复制返回的字符串,而不是丢弃其const-ness.


mch*_*mch 10

const -cast总是......

std::string s("hello world");
char *p = const_cast<char *>(s.c_str());
Run Code Online (Sandbox Code Playgroud)

当然,这基本上颠覆了类型系统,但有时在与旧代码集成时是必要的.

  • -1.当您尝试修改const对象时,您将在此处获得未定义的行为. (7认同)
  • 修改p指向的字符是未定义的行为 - 如果需要强制转换的原因是因为被调用的函数被忽略以标记其参数const,这可能是公平的.如果需要非const指针的原因是因为被调用的函数修改了字符串,那么它就不够公平. (5认同)
  • +1:只检查字符串是否不会更改. (2认同)

Jua*_*uan 5

您可以使用复制方法:

len = myStr.copy(cStr, myStr.length());
cStr[len] = '\0';
Run Code Online (Sandbox Code Playgroud)

哪里myStr是你的C++字符串和cStr一个char *至少myStr.length()+1大小.此外,len是类型size_t和需要,因为副本不会终止cStr.


Dmi*_*try 5

如果您可以负担得起额外的分配,那么建议您strcpy考虑使用以下替代建议的方法std::vector<char>

// suppose you have your string:
std::string some_string("hello world");
// you can make a vector from it like this:
std::vector<char> some_buffer(some_string.begin(), some_string.end());
// suppose your C function is declared like this:
// some_c_function(char *buffer);
// you can just pass this vector to it like this:
some_c_function(&some_buffer[0]);
// if that function wants a buffer size as well,
// just give it some_buffer.size()
Run Code Online (Sandbox Code Playgroud)

对我来说,这比C ++更像是一种C ++方式strcpy。看看Meyers的有效STL项目16,可以得到比我所能提供的更好的解释。

  • 警告:此代码看起来不会导致以空字符结尾的 char* 进入 some_c_function。我不得不添加 some_buffer.push_back(0); 还有 (3认同)

Ann*_*inn 5

只需使用 const_cast<char*>(str.data())

不要为此感到难过或奇怪,这样做是非常好的风格。

它保证在 C++11 中工作。它完全是 const 限定的这一事实可以说是它之前的原始标准的错误;在 C++03 中,可以实现string为不连续的内存列表,但从来没有人这样做过。string除了连续的内存块之外,地球上没有任何编译器可以实现,因此请放心地将其视为这样。