将std::string转换为char*

470

我想将一个 std::string 转换为 char*char[] 数据类型。

std::string str = "string";
char* chr = str;

结果是:“错误:无法将'std::string'转换为'char' ...”

有哪些可用的方法可以解决这个问题?


这个回答解决了你的问题吗?如何将std :: string转换为const char *或char * - ead
18个回答

826

它不会自动转换(谢天谢地)。你需要使用方法 c_str() 来获取 C 字符串版本。

std::string str = "string";
const char *cstr = str.c_str();

请注意,它返回一个const char *;你不允许更改c_str()返回的C风格字符串。如果你想对它进行处理,你需要先复制它:

std::string str = "string";
char *cstr = new char[str.length() + 1];
strcpy(cstr, str.c_str());
// do stuff
delete [] cstr;

或者在现代C ++中:

std::vector<char> cstr(str.c_str(), str.c_str() + str.size() + 1);

5
这是一个示例,实际代码中会使用智能指针,或更有可能完全避免使用 c_str 的混乱。 - orlp
16
答案笨重、不够优雅、不具备本地性、使用了原始数组,并需要特别注意异常安全。vector恰好是专门作为动态数组的包装器而被发明出来的,所以不使用它似乎最多只能算是错失良机,最糟糕的情况则违背了C++的精神。 - Kerrek SB
30
首先,是的,答案有些冗长。我首先解释了 OP 的错误(认为 std::string 会自动转换),然后提供了应该使用的内容,并附上了一个简短的代码示例。同时,我还预测了使用此函数可能产生的一些副作用,其中之一是您可能无法编辑 c_str() 返回的字符串。您错误地将我的简短示例视为实际的问题解决代码,但它不是。 - orlp
9
我给这个回答点了踩。这个答案确实没有用,而且被采纳是非常不幸的事情。这个答案完全忽略了良好的C++编程实践和异常安全性,并且有更优秀的解决方案,其中一些在其他回答中已经给出(例如ildjarn提供的使用std::vector<char>的答案)。 - James McNellis
151
@james-mcnellis,我选择将这个答案选为正确的答案,因为它恰好回答了我所询问的内容... 不多也不少。我没有要求您认为我应该做什么,我没有要求您为您认为我正在做什么提供不同的解决方案,我没有要求您提供良好的实践方法。您不知道我在做什么、我的代码将在什么地方实施以及在什么条件下进行。有些人应该学会阅读、理解问题,并回答实际被问到的问题。这里没有炫耀的必要。 - user912695
显示剩余14条评论

243

更多细节请看这里,以及这里,但是你可以使用

string str = "some string" ;
char *cstr = &str[0];

从 C++11 开始,您还可以使用 str.data() 成员函数,它返回 char *

string str = "some string" ;
char *cstr = str.data();

25
就我看来,这是对实际问题唯一正确的答案。std::string 本质上是可变的,那些声称修改字符串内容像是在干魔鬼的工作的人似乎忽略了这个事实。 - Jay Freeman -saurik-
4
是的,这是正确答案。鉴于使用频繁,没有像微软的lockbuffer那样的标准方法来做这件事情,这真是太傻了。 - Erik Aronesty
1
我将0更改为0u。因为当警告被完全打开时,某些编译器/库会(信不信由你)抱怨&str[0]结构的一些歧义。 - Erik Aronesty
9
请注意,这仅适用于C++11。早期版本可能没有连续的存储空间或缺少终止的空值。 - Flamefire
1
这段代码可以工作,直到字符串超出作用域:char *cstr = nullptr; { string str = "some string" ; cstr = &str[0]; } std::cout< - Cosmo
显示剩余8条评论

50

如果我需要一个可变的C++字符串内容的原始副本,那么我会这样做:

std::string str = "string";
char* chr = strdup(str.c_str());

后来:

free(chr); 

为什么我不想像其他人一样使用std :: vector或new[]? 因为当我需要一个可变的C风格原始char *字符串时,我想调用更改字符串的C代码,并且C代码使用free()来释放资源和使用malloc()来分配资源(strdup使用malloc)。因此,如果我将我的原始字符串传递给某个以C编写的函数X,则该函数可能对其参数有约束,使其必须在堆上分配内存(例如,如果该函数可能希望调用realloc)。但是,它极不可能期望使用(某些用户重新定义的)new []分配的参数!


1
你应该解释一下 strdup 是从哪里来的。 - L. F.

25

(本答案仅适用于C++98。)

请不要使用原始的char*

std::string str = "string";
std::vector<char> chars(str.c_str(), str.c_str() + str.size() + 1u);
// use &chars[0] as a char*

1
今天早些时候我实际上就需要这样的东西。我在想,是否可以说vector<char>(str.c_str(), str.c_str() + str.size() + 1),而不将char指针分配给临时变量? - Kerrek SB
2
@friendzis:以这种方式使用“vector”不会产生速度或空间开销。如果没有RAII机制(即使用原始指针)编写异常安全代码,则代码复杂度要比这个简单的一行式子高得多。 - ildjarn
8
“vector”有巨大的开销和复杂性是一个谬论。如果您需要一个可变的char数组,那么实际上,char向量就是C++中非常理想的包装器。如果您只需要一个const-char指针,那么只需使用“c_str()”即可完成。 - Kerrek SB
1
@ildjarn难道你不能直接使用char * chars =&str [0];而不是创建一个std :: vector作为中介吗? - bobobobo
3
@ildjarn说:实际上,它基本上就是这样。 - Lightness Races in Orbit
显示剩余4条评论

19
  • 如果您只需要一个表示相同内容的C风格字符串:

char const* ca = str.c_str();
  • 如果你想要一个具有新内容的 C 风格字符串,一种方式(假设你在编译时不知道字符串大小)是进行动态分配:

  • char* ca = new char[str.size()+1];
    std::copy(str.begin(), str.end(), ca);
    ca[str.size()] = '\0';
    

    别忘了以后要用 delete[] 删除它。

  • 如果你想要一个静态分配的、长度有限的数组:

  • size_t const MAX = 80; // maximum number of chars
    char ca[MAX] = {};
    std::copy(str.begin(), (str.size() >= MAX ? str.begin() + MAX : str.end()), ca);
    

    std::string 不会隐式转换为这些类型,因为通常需要这样做是设计上的问题。确保你确实需要它。

    如果你绝对需要一个 char*,最好的方法可能是:

    vector<char> v(str.begin(), str.end());
    char* ca = &v[0]; // pointer to start of vector
    

    1
    为什么使用 &str.front(), &str.back()(在 C++03 中不存在)而不是更常见的 str.begin()str.end() - Armen Tsirunyan
    1
    str.begin()怎么样?甚至是std::begin(str),类似于迭代器?我不认为string有像vector一样必须在连续内存中的义务,难道有吗? - xtofl
    1
    @xtofl:我已经编辑好了。是的,从C++11开始有这个义务;这在C++03中是隐含的。 - Lightness Races in Orbit
    1
    @Tomalak:它们被误用了,因为你需要&back() + 1而不是&back() - Armen Tsirunyan
    相比你上一个例子中的创建、调整大小和复制混乱,使用 vector<char> v(str.begin(), str.end()) 更加简洁明了,而且更为重要的是它更加短小精悍。 - Christian Rau
    显示剩余8条评论

    13

    这应该作为对bobobobo的答案的评论,但我没有足够的声望来这样做。它可以实现相同的效果,但是使用更好的实践。

    虽然其他答案也有用,但如果您需要明确将std ::string转换为未带const的char*,那么const_cast就是您的朋友。

    std::string str = "string";
    char* chr = const_cast<char*>(str.c_str());
    

    请注意,这将不会给您数据的副本;它将为您提供指向字符串的指针。因此,如果您修改了chr的元素,则会修改str


    1
    API 设计者将返回的指针设为 const char* 而不是 char *,可能有很好的理由。const 表示“不要修改这个对象”。当你使用 const_cast 时,你在说“我知道得更好,我真的可以修改这个对象。”或者你在说“我不会修改这个对象,我只需要通过这个函数传递它,但这个函数没有声明它的输入是 const 的。”虽然似乎安全地丢弃 C 字符串的 const 特性,因为我们知道它是可变数据,但你真的不应该这样做。尽可能避免使用 const_cast - bobobobo
    正确。有时候,你必须与旧的API进行接口,并且没有重写整个代码以使其“干净和纯粹”的奢侈条件。由于在我的VS上,std::string.data()返回const char*,因此为一些旧方法(在std::string出现之前就已经经过生产测试)去除const属性绝对是正确的做法。对于我的情况来说。 - 3D Coder

    9
    从一个 std::string 获取一个 const char *,可以使用 c_str() 成员函数:
    std::string str = "string";
    const char* chr = str.c_str();
    

    如果要从 std::string 中获取非常量 char *,可以使用自 C++17 以来返回非常量指针的 data() 成员函数:

    std::string str = "string";
    char* chr = str.data();
    

    对于旧版本的语言,您可以使用范围构造将字符串复制到向量中,从而可以获得非const指针:

    std::string str = "string";
    std::vector<char> str_copy(str.c_str(), str.c_str() + str.size() + 1);
    char* chr = str_copy.data();
    

    但要注意,这不会让您修改str中包含的字符串,仅可以通过复制数据来进行更改。请注意,在旧版本的语言中特别重要使用c_str(),因为在那个时候std::string在调用c_str()之前不能保证以空字符结尾。


    8
    假设你只需要一个 C 风格的字符串作为输入:
    std::string str = "string";
    const char* chr = str.c_str();
    

    5
    这里有一个更加强大的版本来自于Protocol Buffer
    char* string_as_array(string* str)
    {
        return str->empty() ? NULL : &*str->begin();
    }
    
    // test codes
    std::string mystr("you are here");
    char* pstr = string_as_array(&mystr);
    cout << pstr << endl; // you are here
    

    +1 是为了检查字符串是否为空。我还会添加一个检查,以确保字符串是以零结尾的:if (str[str.length()-1] != 0) str.push_back(0) - GaspardP

    5
    严格来说,您不能“将std :: string转换为char *或char []数据类型”。
    正如其他答案所示,您可以将std :: string的内容复制到char数组中,或者创建const char *以访问std :: string中的内容。
    如果您想要更改std :: string的内容,则std :: string类型具有完成所有必要任务的方法。
    如果您想将其传递给某个需要char *的函数,则可以使用std :: string :: c_str()。

    1
    不正确。如果您需要将其传递给一些需要char的旧API函数,则c_str()*无法使用,因为它返回const char *。 - 3D Coder

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接