理解C++字符串

Duh*_*Duh 4 c++ string c++11

我试图理解字符串在C++中是如何工作的,因为在遇到意外行为后我真的很困惑.

考虑一个字符串,我append()使用[]运算符插入一个字符(不使用):

string str;
str[0] = 'a';
Run Code Online (Sandbox Code Playgroud)

让我们打印字符串:

cout << "str:" << str << endl;
Run Code Online (Sandbox Code Playgroud)

我得到NULL作为输出:

str:
Run Code Online (Sandbox Code Playgroud)

好的,让我们尝试打印字符串中唯一的字符:

cout << "str[0]:" << str[0] << endl;
Run Code Online (Sandbox Code Playgroud)

输出:

str[0]:a
Run Code Online (Sandbox Code Playgroud)

Q1.那里发生了什么?为什么a不在第一种情况下打印?

现在,我做了一些应该抛出编译错误的东西,但它没有,我的问题又是,为什么.

str = 'ABC';
Run Code Online (Sandbox Code Playgroud)

Q2.那不是一个不正确的语义,即将字符(实际上不是字符,但实际上是单引号中的字符串)分配给字符串?

现在,更糟糕的是,当我打印字符串时,它总是打印最后一个字符,即C(我期待第一个字符,即A):

cout << "str:" << str << endl;
Run Code Online (Sandbox Code Playgroud)

输出:

str:C
Run Code Online (Sandbox Code Playgroud)

Q3.为什么打印最后一个字符,而不是第一个?

eer*_*ika 5

考虑一个字符串,我使用[]运算符插入一个字符(不使用append()):

string str;
str[0] = 'a';
Run Code Online (Sandbox Code Playgroud)

你没有插入一个角色.operator[](size_type pos)返回对 - 已存在 - 字符的引用pos.如果pos == size()那么行为是未定义的.您的字符串为空,size() == 0因此str[0]具有未定义的行为.

Q1.那里发生了什么?为什么在第一种情况下不打印?

行为未定义.


现在,我做了一些应该抛出编译错误的东西,但它没有,我的问题又是,为什么.

str ='ABC';

Q2.怎么不是一个不正确的语义,即将一个字符...分配给一个字符串?

将字符分配给字符串不是不正确的语义.它将字符串的内容设置为该单个字符.

Q2....一个字符(实际上不是一个字符,但实际上是单引号中的字符串)...

这是一个多字符文字.多字符文字的类型是int.如果编译器支持多字符文字,则语义不正确.

字符串的赋值运算符不会接受int.但是,int可以隐式转换为char,因此char在转换后使用接受a的赋值运算符.

char不一定能代表所有可能的值int,因此转换可能会溢出.如果char是签名类型,则此溢出具有未定义的行为.


Q3.为什么打印最后一个字符,而不是第一个?

多字符文字的值是实现定义的.您需要查阅编译器的手册,以确定是否支持多字符文字,以及您应该期望的值.此外,您需要考虑这样一个事实,char即转换为值可能无法表示所有值int.


但我没有得到任何警告

然后考虑获得更好的编译器.这是GCC警告的:

警告:多字符字符常量[-Wmultichar]

 str = 'ABC';
Run Code Online (Sandbox Code Playgroud)

警告:隐式常量转换溢出[-Woverflow]


str[0] = 'a'应该像使用字符串一样使用字符串char str[] = ""(但它不像我们看到的那样).你能帮助我理解为什么[]运算符在处理字符数组时的行为与字符串不同吗?

因为这就是标准如何定义行为和要求std::string.

char str[] = "";
Run Code Online (Sandbox Code Playgroud)

创建一个大小为1的数组,由null终止符组成.该数组的元素与其他元素一样,您可以自由地修改它:

str[0] = 'a';
Run Code Online (Sandbox Code Playgroud)

这是明确定义的,没问题.但现在str不再包含以null结尾的字符串,因此尝试使用它具有未定义的行为:

out << "str:" << str << endl; // oops, str is not a null terminated string
Run Code Online (Sandbox Code Playgroud)

所以,std::string设计成你不能搞乱最终的空终止符 - 只要你遵守要求std::string.不允许触摸空终止符也允许实现永远不为空字符串分配内存缓冲区.不分配内存可能比分配内存更快,所以这是一件好事.