程序:
#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
为什么我的程序会这样?如何在不更改数据类型的情况下更改代码以获得所需的输出?
答案 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
已经是未定义行为的事实。症状可能看起来是良性的,但这种疾病是致命的。