0. 课堂视频
1. 分支流程
最常见的程序执行流程,是一条路顺序走到底,称为“顺序流程”,比如:
语句1;
语句2;
语句3;
语句4;
执行过程(为节约版面,横着摆)就是:
但人生最不缺的,就是选择。有时候,我们希望在执行完语句1之后,如果具备某个条件,才执行语句2,否则执行语句3;最后再执行语句4,这时的流程就是一个典型的选择分支流程。
- 流程图
注意,上图中,语句1在分支之前,语句4在分支之后,因此都是必经之路,必做的步骤;二者并不属于分支流程的组成。
套用课程视频里老师所说的 “差别式问候”,则有:
- 条件1:指当前遇到的XXX,是不是 “志玲”;
- 语句2:当条件1成立,执行的语句,即对女神的问候;
- 语句3:当条件1不成立,执行的语句,即普通问候。
下面给出典型的 if/else 代码结构和实际使用案例代码——
- 代码结构:
if (条件1)
{
// 条件1成立时,走这里的代码
}
else
{
// 否则(即:条件1不成立),走这里的代码
}
- 案例代码:
void Hello(std::string_view XXX)
{
if (XXX == "志玲")
{
std::cout << "你好,志玲,你很美,你是站长的女神" << std::endl;
}
else
{
std::cout << "你好," << XXX << "!" << std::endl;
}
}
如果需要区分处理的情况,有更多个,那就需要多级 if / else if / else if / …,我们先给三级的情况:
- 代码结构:
if (条件1)
{
// 条件1成立时,走这里的代码
}
else if (条件2)
{
// 条件1不成立,但条件2成立,走这里的代码
}
else
{
// 条件1和2都不成立,走这里的代码
}
- 案例代码:
void Hello(std::string_view XXX)
{
if (XXX == "志玲")
{
std::cout << "你好,志玲,你很美,你是站长的女神" << std::endl;
}
else if (XXX == "老板娘")
{
std::cout << "你好,财神!" << std::endl;
}
else
{
std::cout << "你好," << XXX << "!" << std::endl;
}
}
2. 比较运算
在分支结构的条件判定中,经常需要用到比较运算。常见的比较运算符如:
- == (是否相等,注:可能是内容相等比较,也可能是实体相等比较)
- >、>=、<、<= (是否大于、大于等于、小于、小于等于,同样有可能是在比较内容大小,也可能是在比较实体,即数据所在地址/“门牌号码”的大小)
2.1 实体 vs. 内容
- 程序中数据的实体,是指这个数据所拥有的独立身份,即它所存在的内存地址。
- 程序中数据的内容,是指这个数据所拥有的内容,即它所存在的内存所存储的值。
比如,下图所示的内存中,有两个字符串,二者实体地址不同(一个701,一个705),但内容相同:
2.2 正确比较字符串
依据数据类型不同,比较操作有可能是在比较数据的内容,也可能是在比较数据的实体(所在内存地址)。
纯C风格的字符串(即字符指针)比较,比较的是实体,所以:
if ("志玲" == "志玲")
{
cout << "志玲就是读者老婆" << endl; // 这句话基本不可能输出
}
或者:
char const* a = "志玲"; // 定义一个常量字符串指针,变量定义见上节
char const* b = "志玲";
if (a == b)
{
cout << "志玲就是读者老婆" << endl; // 这句话基本不可能输出
}
不能说志玲就绝对不可能是读者的老婆,因为在特定编译条件设定下,以及编译优化下,上面条件有可能成立,此时两个内容相同的字符串,会被编译器刻意实现成就是同一个实体;但是!我们写的程序,一定不能依赖于这个比较结果,因为在复杂的程序中,这个相等结果无法保障。
编译器之所以会在此类情况下,做优化,主要是为了节省内存:让所有内容相同的字符串,就变成是同一个字符串。程序逻辑不能依赖于优化的“副”作用。
下面代码即是一个内容相等,但实体确保不等(给编译器十个胆子,也不敢优化):
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char* a = new char[4]; // 给a单独分配一块内存
std::strcpy(a, "AAA"); // 并使用 "AAA" 填充其内容
if (a == "AAA") // 肯定不等
{
cout << "a is AAA" << endl;
}
}
业务程序中的多数情况,当我们比较字符串时,希望比较的是内容,C++ 标准库的 std::string以及来自17新标的 std::string_view ,体现了这一点。因此,假设有:
std::string a1 = "AAA";
std::string a2 = "AAA";
std::string_view av1 = a1;
std::string_view av2 = a2;
则以下相等比较都成立:
- a1 == a2
- a1 == av1
- a2 == av1
- a2 == av2
- av1 == av2
为了进一步方便 “比较字符串内容”,而非“比较字符串实体”,C++还实现了一点小小的“智能”:只要等号(==)两边有一个是 std::string 或 std::string_view,则另一边的数据,在存在可能的情况下——即程序中存在允许将该数据隐式的一步转换成std::string 或std::string_view 时——编译器就会做这个转换,从而实现 == 两边都是 std::string 或 std::string_view后,再作比较。
3. 逻辑运算 || 和 &&
在分支结构的条件判定中,经常需要用到逻辑(组合)运算。
- && 是“并且/AND”的意思,左右两个条件都为真,结果才是真。
- || 是“或者/OR”的意思,左右两个条件有一个为真,结果就是真。
所以,如果我们认定志玲和娜扎都是女神,那么,以下条件就写得很棒:
if (XXX == "志玲" || XXX == "娜扎")
{
cout << "你好," << XXX << ",女神!" << endl;
}