std :: string复制构造函数是否在最后添加空字符?

时间:2014-05-01 16:29:10

标签: c++ function stl iostream

首先我在做,

#include <iostream>
#include <string>

void foo (std::string s) {
    std::cout << s << std::endl;
}

int main () {
    char st[] = "0";
    st[1] = '[';
    std::string s (st);
    std::cout << s << std::endl;
    return 0;
}

当我使用流插入运算符发送到流对象cout时,它显示垃圾(猜测这是正常行为)。

然后我按值传递给函数foo进行检查。 我现在正在做这样的事情。

    foo (s);

    // after calling foo () value printed by the
    // std::cout is changed. it takes care of NULL character ('\0')
    std::cout << s << std::endl;

它不会在0[之后显示垃圾。为什么呢?

我的问题是, 我按值foo ()传递了字符串。在foo ()的主体运行之前运行一个复制构造函数。但仍然没有意义。这个copyctor更改参数如何通过值从main ()传递?

提前致谢。

4 个答案:

答案 0 :(得分:10)

char st[] = "0";

流行测验:st有多大?

答案:两个chars一个用于"0“,一个用于空终止符。

然后你去覆盖空终止符:

st[1] = '[';

...并尝试根据以下内容构建string

std::string s (st);

这里调用了string const char*构造函数,它的工作方式是查找null终止符。自从你把它吹走之后,它将会超过st的末尾。跑过st的末尾会唤起未定义的行为,这就是你看到垃圾的原因。

重要的是要注意,未定义的行为意味着任何都可能发生。这里的“任何东西”包括“我想要发生的事情”。它不一定会得到垃圾输出,或者你的程序会崩溃。试图弄清楚为什么UB以这种方式表现出来或者这是一种无理的努力。

答案 1 :(得分:3)

人们告诉你未定义的行为。这很棒,但你已经知道了。

在实践中,关键是你的第一个&#34;垃圾&#34;字符本身可能是'\0'字符,在这种情况下,您不会再看到任何字节。

您不能假设您将至少看到20个任意字符,因为您的代码的一个完全合理的结果是您看到0个任意字符。

简而言之,你试图使不合理的人合理化;停下来!

答案 2 :(得分:1)

这两行之后:

char st[] = "0";
st[1] = '[';

st不是以空字符结尾的字符串。 std::string(char const*)期望一个以空字符结尾的字符串。由于std:string的构造函数的输入不符合该标准,因此您输入的是未定义的行为区域。之后可能发生任何事情。

答案 3 :(得分:1)

这一行:

char st[] = "0";

使编译器分配一个2字节数组的固定大小数组,并用&#34; 0 \ 0&#34;填充它。 (ASCII 0后跟空字符)。这一行

st[1] = '[';

然后分配&#39; [&#39;到之前被NULL占用的位置,破坏了字符串的空终止。然后这一行

std::string s (st);

将从st的开头开始,并继续将字符复制到s,直到它在内存中的某处找到空值。这就是你看到垃圾的原因。