如何将const char*转换为std::string

34

如何正确/最佳/最简单地将C风格字符串转换为std::string?

转换应该接受一个max_length参数,并且在第一个\0字符出现之前,如果在max_length个字符之内遇到\0,则截断字符串。


12
使用构造函数。 - Kerrek SB
如果我使用类似于std::string s(c_sting, length)的构造函数,它将在第一次出现\0时结束字符串。 - Allan
或赋值根据接收者的生命周期工作。 - crashmstr
1
@Allan:那就使用另一个构造函数,它接受指向以空字符结尾的字符串的指针 :-) - Kerrek SB
6个回答

31
这个页面关于string::string提供了两个可能符合您需求的构造函数:
string ( const char * s, size_t n );
string ( const string& str, size_t pos, size_t n = npos );

例子:

#include<cstdlib>
#include<cstring>
#include<string>
#include<iostream>
using namespace std;

int main(){

    char* p= (char*)calloc(30, sizeof(char));
    strcpy(p, "Hello world");

    string s(p, 15);
    cout << s.size() << ":[" << s << "]" << endl;
    string t(p, 0, 15);
    cout << t.size() << ":[" << t << "]" << endl;

    free(p);
    return 0;
}

输出:

15:[Hello world]
11:[Hello world]

第一种形式将p视为简单数组,因此将创建一个长度为15的字符串,在使用cout << ...打印时会作为一个11个字符的以null结尾的字符串。这可能不是您要寻找的内容。
第二种形式将隐式转换char*为字符串,然后保留其长度和指定的n之间的最大值。我认为这是最简单的解决方案,就编写所需内容而言。

calloc + delete??? - The Techel
1
好的,没问题 :) - Vlad
嗯,也不是很像C++,但还可以。 - The Techel

14

1
strnlen是标准的C++函数吗?如果不是,您应该提到这种非可移植性。 - Christian Rau
@ChristianRau:这是一个POSIX标准函数,但并非普遍可用。我已经扩展了我的答案。 - ephemient

5
std::string the_string(c_string);
if(the_string.size() > max_length)
    the_string.resize(max_length);

2
如果c_string没有正确地以NULL结尾,会发生什么? - Allan
7
C风格的字符串应始终以NULL结尾。 - crashmstr

5

这实际上比看起来要棘手得多,因为你不能调用strlen除非字符串实际上是以nul结尾的。实际上,如果没有一些额外的限制条件,这个问题几乎需要发明一个新函数,一个strlen的版本永远不会超过某个长度。但是:

如果包含C风格字符串的缓冲区至少保证是max_length字符(可能在末尾有'\0'),那么可以使用std::string的地址-长度构造函数,并在之后修剪:

std::string result( c_string, max_length );
result.erase( std::find( result.begin(), result.end(), '\0' ), result.end() );

如果你知道c_string是以空字符结尾的字符串(但可能比max_length长),你可以使用strlen

std::string result( c_string, std::min( strlen( c_string ), max_length ) );

0

有一个接受两个指针参数的构造函数,所以代码很简单

 std::string cppstr(cstr, cstr + min(max_length, strlen(cstr)));

如果长度小于max_length,那么这也将像std::string cppstr(cstr)一样高效。


你也可以使用接受指针和长度作为参数的构造函数,不需要进行指针运算(尽管实际上没有太大区别)。从技术上讲,它并不接受两个指针参数,而是接受两个迭代器参数。顺便说一下,这种方法的效率不如O(n)的解法高,它的时间复杂度是O(2n),而且常数项也很重要。不过,它当然仍然是一个正确的解决方案。 - Christian Rau
@ChristianRau:使用C字符串需要进行一次扫描以了解长度(需要分配多少空间),但不需要进行第二次扫描(构造函数可以通过减去两个指针来获取大小)。因此,需要进行一次长度扫描和一次复制扫描:这是除非您愿意浪费空间,否则您可以做的最少量。 - 6502

-2
你需要的是这个构造函数:std::string ( const string& str, size_t pos, size_t n = npos ),将pos作为0传递。你的const char* C风格字符串将会被隐式转换为第一个参数的const string类型。
const char *c_style = "012abd";
std::string cpp_style = std::string(c_style, 0, 10);

更新:从 cpp_style 初始化中删除了 "new"


我不是那个点踩者,但在这种情况下operator new是完全多余的,对于std::string来说栈分配就可以了(它太像Java了)。 - Alessandro Teruzzi
修正了对new的使用 - kbyrd

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