std :: string构造函数如何处理固定大小的char []?

时间:2018-10-17 11:43:33

标签: c++ string c++11

char[]中的实际字符序列可能小于最大大小时,字符串构造器如何处理固定大小的char[]

char foo[64];//can hold up to 64
char* bar = "0123456789"; //Much less than 64 chars, terminated with '\0'
strcpy(foo,bar); //Copy shorter into longer
std::string banz(foo);//Make a large string

在此示例中,banz对象字符串的大小将基于原始char *长度还是将其复制到的char []中?

2 个答案:

答案 0 :(得分:7)

首先,您必须记住(或知道)C ++中的char字符串实际上称为 以空值结尾的 字节字符串以null结尾的位是一个特殊字符('\0'),它指示字符串的结尾。

您要记住(或知道)的第二件事是数组自然会衰减到指向数组第一个元素的指针。对于您示例中的foo,当您使用foo时,编译器实际上会执行&foo[0]

最后,如果我们看例如this std::string constructor reference,您将看到有一个接受const CharT*的重载(数字5)(对于正常的CharT字符串,charchar)。 / p>

通过

将所有内容放在一起
std::string banz(foo);

您将指针传递到foo的第一个字符,并且std::string构造函数会将其视为以空字符结尾的字节字符串。通过找到空终止符,它知道字符串的长度。数组的实际大小无关紧要,不会使用。

如果要设置std::string对象的大小,则需要通过传递长度参数(构造函数参考中的变量4)来明确地做到这一点:

std::string banz(foo, sizeof foo);

这将忽略空终止符,并将banz的长度设置为数组的大小。请注意,空终止符仍将存储在字符串中,因此将指针(例如通过c_str函数检索)传递给期望以空终止字符串的函数,则该字符串看起来很短。另请注意,空终止符之后的数据将未初始化,并且具有不确定的内容。 必须在使用该数据之前对其进行初始化,否则您将拥有undefined behavior(在C ++中,即使读取不确定的数据也将是UB)。


如MSalters的评论中所述,从读取未初始化且不确定的数据的UB也将使用显式大小来构造banz对象。它通常会起作用,不会导致任何问题,但是确实会违反C ++规范中列出的规则。

修复起来很容易:

char foo[64] = { 0 };//can hold up to 64

上面的代码会将数组的 all 初始化为零。以下strcpy调用将不会触及终止符之外的数组数据,因此将初始化数组的其余部分。

答案 1 :(得分:4)

被调用的构造函数是一个以const char*作为参数的构造函数。该构造函数尝试复制该指针指向的字符数据,直到到达第一个NUL终止符。如果没有这样的NUL终止符,则构造函数的行为为 undefined

您的foo类型通过指针衰减转换为char*,然后在调用站点处隐式转换为const char*

也许可能有一个以std::string作为参数的模板化const char[N]构造函数,这将允许插入多个NUL字符(std::string类毕竟可以对此表示支持),但是没有引入它,而现在这样做将是一项重大突破;使用

std::string foo{std::begin(foo), std::end(foo)};

还将复制整个数组foo