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

时间:2009-12-17 05:19:57

标签: c++ c string

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

编辑:我也在努力避免调用新内容。我会很乐意交换稍微复杂的代码,以减少内存泄漏。

13 个答案:

答案 0 :(得分: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());

由于没有已知的实现实际使用非连续内存,并且由于std::string被许多人使用,好像这是有保证的,因此规则将针对即将推出的标准进行更改,现在为其保证连续内存字符。所以在C ++ 1x中,这应该有效:

foo(&s[0], s.size());

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

答案 1 :(得分:12)

你需要在这里做一个重要的区别:你希望将“{1}}指定为”道德常数“吗?就是说,抛弃char* - 只是一种技术性,你真的仍然会将字符串视为const吗?在这种情况下,您可以使用强制转换 - C样式或C ++样式const。只要你(以及任何曾经维护此代码的人)都有纪律将const_cast视为char*,你就没事了,但是编译器将不会再看你的了,因此,如果您将其视为非const char*,则可能正在修改代码中其他内容依赖的缓冲区。

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

答案 2 :(得分:11)

我想总有strcpy

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

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

答案 3 :(得分:9)

总是有const_cast ......

std::string s("hello world");
char *p = const_cast<char *>(s.c_str());

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

答案 4 :(得分:5)

您可以使用copy方法:

len = myStr.copy(cStr, myStr.length());
cStr[len] = '\0';

其中myStr是您的C ++字符串,cStr char *至少myStr.length() + 1大小。此外,len的类型为size_t且需要,因为副本不会终止cStr

答案 5 :(得分: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()

对我而言,这比strcpy更像是一种C ++方式。看一下迈耶斯的有效STL第16项,以获得比我所能提供的更好的解释。

答案 6 :(得分:2)

如果您知道std::string不会改变,那么C风格的演员阵容将起作用。

std::string s("hello");
char *p = (char *)s.c_str();

当然,p指向由std::string管理的某个缓冲区。如果std::string超出范围或缓冲区已更改(即写入),则p可能无效。

最安全的做法是复制字符串,如果重构代码是不可能的。

答案 7 :(得分:2)

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

即可

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

它保证可以在C ++ 11中运行。它的const符合条件这一事实可以说是它之前的原始标准的错误;在C ++ 03中,有可能将string实现为不连续的内存列表,但没有人做过。世界上没有一个编译器将string实现为连续的内存块以外的其他任何东西,所以请完全放心地对它进行处理。

答案 8 :(得分:1)

如果c_str()返回给你一个字符串对象内部缓冲区的副本,你可以使用const_cast<>

但是,如果c_str()让您直接访问字符串对象内部缓冲区,请进行显式复制,而不是删除const。

答案 9 :(得分:1)

由于c_str()为您提供了对数据结构的直接const访问,因此您可能不应该强制转换它。在不必预先分配缓冲区的情况下,最简单的方法就是使用strdup。

char* tmpptr;
tmpptr = strdup(myStringVar.c_str();
oldfunction(tmpptr);
free tmpptr;

快速,简单,正确。

答案 10 :(得分:1)

std::string vString;
vString.resize(256); // allocate some space, up to you
char* vStringPtr(&vString.front());
// assign the value to the string (by using a function that copies the value).
// don't exceed vString.size() here!
// now make sure you erase the extra capacity after the first encountered \0.
vString.erase(std::find(vString.begin(), vString.end(), 0), vString.end());
// and here you have the C++ string with the proper value and bounds.

这就是你将C ++字符串转换为C字符串的方式。但请确保你知道自己在做什么,因为使用原始字符串函数很容易超出界限。有时候这是必要的。

答案 11 :(得分:0)

在CPP中,如果您要从char *中获取string.c_str() (例如,将其赋予仅包含char *的函数), 您可以将其直接投射到char *,以使const失去.c_str()

示例:

launchGame((char *) string.c_str());

答案 12 :(得分:-3)

自己真的很难吗?

#include <string>
#include <cstring>

char *convert(std::string str)
{
    size_t len = str.length();
    char *buf = new char[len + 1];
    memcpy(buf, str.data(), len);
    buf[len] = '\0';
    return buf;
}

char *convert(std::string str, char *buf, size_t len)
{
    memcpy(buf, str.data(), len - 1);
    buf[len - 1] = '\0';
    return buf;
}

// A crazy template solution to avoid passing in the array length
// but loses the ability to pass in a dynamically allocated buffer
template <size_t len>
char *convert(std::string str, char (&buf)[len])
{
    memcpy(buf, str.data(), len - 1);
    buf[len - 1] = '\0';
    return buf;
}

用法:

std::string str = "Hello";
// Use buffer we've allocated
char buf[10];
convert(str, buf);
// Use buffer allocated for us
char *buf = convert(str);
delete [] buf;
// Use dynamic buffer of known length
buf = new char[10];
convert(str, buf, 10);
delete [] buf;