为什么我的字符串变量不能打印完整的字符串?

时间:2020-02-02 13:50:20

标签: c++

程序:

#include <iostream>
using namespace std;

int main() {
    string str;
    str[0] = 'a';
    str[1] = 'b';
    str[2] = 'c';

    cout << str;

    return 0;
}

输出:

无输出。


如果将cout << str;替换为cout << str[1],则会得到正确的输出。

输出:

b

如果我将变量的数据类型更改为字符数组,则会得到所需的输出。 (用string str;代替char str[5];

输出:

abc

为什么我的程序会这样?如何在不更改数据类型的情况下更改代码以获得所需的输出?

2 个答案:

答案 0 :(得分:5)

您的程序有未定义的行为。

string str;

创建一个空字符串。它的长度为0

您正尝试使用以下命令写入此字符串的前三个元素

str[0] = 'a';
str[1] = 'b';
str[2] = 'c';

这些不存在。索引std::string越界会导致不确定的行为。

您可以使用以下任何一种方法将字符添加到字符串中:

str += 'a';
str += "a";
str.push_back('a');
str.append("a");

或者您可以先将字符串的大小调整为预期的长度,然后再索引其任何元素:

str.resize(3);

正如@Ayxan在此答案下的评论中指出的那样,您也缺少#include<string>。如果没有它,则未指定,因为它使用std::string中定义的<string>,所以您的程序是否将编译。 未指定,如果没有特定的例外,是否包含一个标准库头是否将包含另一个标准库头。您不应该依赖可能在任何时候中断的未指定行为。

答案 1 :(得分:0)

除了walnut's answer,这是幕后故事:

x至少包含两个成员,一个数据指针(类型std::string)和一个大小。 char*操作符不检查大小,它仅索引到数据指针后面的内存中。另外,[]运算符不会修改字符串的大小成员。

将字符串流传输到[]的{​​{1}}运算符会解释大小成员。这样做是为了能够输出包含空字符的字符串。由于size成员仍为零,因此不会打印任何内容。


您可能想知道为什么<<内的内存访问即使成功,毕竟该字符串还没有任何理由为其数据分配任何内存。这是由于以下事实:实际上,所有cout实现都使用小字符串优化:str[0]对象本身比实际需要的要大一些,而使用其末尾的空间代替除非字符串变得比该空间长,否则在堆上分配。这样,默认构造函数将只将数据指针指向该内部存储器以对其进行初始化,并且您的内存访问将定向到现有内存。这就是为什么除非您超出范围访问字符串的数据方式,否则您不会得到SEGFAULT的原因。不过,这不会改变您的表达式std::string已经是未定义行为的事实。症状可能看起来是良性的,但这种疾病是致命的。