将非空结尾的无符号字符数组复制到std :: string中

55

如果数组以null结尾,那么这将非常简单:

unsigned char u_array[4] = { 'a', 's', 'd', '\0' };
std::string str = reinterpret_cast<char*>(u_array);
std::cout << "-> " << str << std::endl;

然而,我想知道最合适的方式是如何复制一个非空结尾的无符号字符数组,就像下面这样:

unsigned char u_array[4] = { 'a', 's', 'd', 'f' };

如何将无符号字符数组快速转换为std::string

谢谢大家。

12个回答

66

std::string提供了一个接受迭代器对的构造函数,而unsigned char可以被转换成char(以实现定义的方式),因此可以直接使用这个构造函数,不需要使用reinterpret_cast

unsigned char u_array[4] = { 'a', 's', 'd', 'f' };

#include <string>
#include <iostream>
#include <ostream>

int main()
{
    std::string str( u_array, u_array + sizeof u_array / sizeof u_array[0] );
    std::cout << str << std::endl;
    return 0;
}

当然,“数组大小”模板函数比sizeof计算更加健壮。


1
@VladLazarenko:但我不想进行那种转换。 - CB Bailey
2
@Charles,别再使用有缺陷的编译器了。你需要调用的构造函数签名是std::string (const char *, size_t),因为unsigned不能隐式转换为signed,传递unsigned char *会引入歧义。请使用正确的编译器进行检查,或者参考这个例子 - https://dev59.com/AnRA5IYBdhLWcg3w2xwI - user405725
6
FYI,通过sizeof u_char[0]进行除法运算是完全多余的。标准已经保证该大小与char的大小相等,而根据定义,char的大小为1。 - Konrad Rudolph
6
@Konrad:我相信Charles选择展示通用代码,以免误导读者只是为了例如wchar_t而进行sizeof - Cheers and hth. - Alf
7
你可以简单地将第二个参数替换为std::end(u_array)(C++0x)。 - Blastfurnace
显示剩余7条评论

28

看起来,std::string 有一个可以用于这种情况的构造函数

std::string str(reinterpret_cast<char*>(u_array), 4);

3
更多的是意识形态上的思考,但最好不要放弃数组的常数性。此外,应该使用其大小而不是硬编码容易出错的“4”。 - user405725

8

构建字符串时,如果没有明确指定大小,构造函数将遍历字符数组并查找空终止符,即 '\0' 字符。如果您没有该字符,则必须明确指定长度,例如:

// --*-- C++ --*--

#include <string>
#include <iostream>


int
main ()
{
    unsigned char u_array[4] = { 'a', 's', 'd', 'f' };
    std::string str (reinterpret_cast<const char *> (u_array),
                     sizeof (u_array) / sizeof (u_array[0]));
    std::cout << "-> " << str << std::endl;
}

4
这应该就可以了:
std::string s(u_array, u_array+sizeof(u_array)/sizeof(u_array[0]));

u_array 是无符号字符类型,而 std::string 的构造函数需要 const char *,所以这段代码甚至无法编译通过。 - user405725
@Vlad Lazarenko:不,我检查过了,应该没问题。 - cpx
@VladLazarenko:一个“unsigned char”可以被转换为“char”,它们都是整数类型(例如:“char x =(unsigned char)10;”)。如果“unsigned char”的值不能被表示为“char”,则结果是实现定义的,但这是一个有效的转换。 - CB Bailey
@Charles:当然可以转换。但是它们不能隐式转换。你的编译器默认情况下必须将char作为unsigned,这是有道理的,但不是标准的,我猜测。或者它必须非常聪明地查看编译时常量数组,并决定它可以转换为带有有符号值的数组。 - user405725
1
@VladLazarenko:任何整数类型都可以转换为任何其他整数类型:4.7 [conv.integral]。这包括“unsigned char”和“char”。 - CB Bailey
显示剩余2条评论

3

您可以使用以下 std::string 构造函数:

string ( const char * s, size_t n );

因此,在你的例子中:

std::string str(u_array, 4);

1
你可以通过使用 sizeof (u_array) 来改进它。甚至更好的方法是使用 sizeof (u_array) / sizeof(u_array[0]),这将适用于数据类型大小大于1字节的情况。 - user405725

3

2
它还有一个接受字符指针和大小的构造函数。在你还没有字符串实例的情况下,使用构造函数是有意义的。 - user405725
这种情况的问题在于,您不知道字符串占用了多少字节,并且不确定使用 .c_str() 是否会给您一个有效的 C 字符串。 - user595447

1
你可以创建一个指向第一个字符的字符指针,另一个指向最后一个字符的下一个位置,并使用这两个指针作为迭代器进行构造。因此:
std::string str(&u_array[0], &u_array[0] + 4);

1
这种方法容易出错,因为数组的大小可能会改变,而你可能很容易忘记用新值替换你的 4。此外,使用 &u_array[0] 没有任何意义,它等同于只使用 u_array,而且打字量更少。 - user405725

1

当字符串本身包含空字符并且您随后尝试打印该字符串时,仍然存在问题:

char c_array[4] = { 'a', 's', 'd', 0 };

std::string toto(array,4);
cout << toto << endl;  //outputs a 3 chars and a NULL char

然而...

cout << toto.c_str() << endl; //will only print 3 chars.

在这种时候,你只想放弃可爱的东西,使用裸露的C语言。


1
尽管问题是如何“将一个非空结束的unsigned char数组[...]复制到std::string中”,但我注意到在给定的示例中,该字符串仅用作std::cout的输入。
在这种情况下,当然可以完全避免使用字符串,而只需执行:
std::cout.write(u_array, sizeof u_array);
std::cout << std::endl;

我认为这可能解决了原帖作者试图解决的问题。


0

尝试:

std::string str;
str.resize(4);
std::copy(u_array, u_array+4, str.begin());

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