C++ 的选择逻辑包含 if-else 语句与 switch 语句,为程序提供了一种有条件地执行代码块的方式。
C++编程中,if-else 语句用于测试条件。C++ 包含如下类型的 if-else 语句:if 语句、if-else 语句、嵌套 if 语句以及 if-else-if 梯形语句。
if-else 语句基本语法如下:
if( condition )
{
if-branch
}
else if( condition )
{
else-if-branch
}
else
{
else-branch
}
if-else 语句控制条件分支逻辑:当 condition 计算结果为非零值时,会执行 if-branch 语句。否则,如果存在 else ,将执行 else-branch 语句。
(1)判断条件的结果
计算结果为非零的 condition 表达式包括:true、非 null 指针以及任何非零算术值,因此 if( -1 )
也会判断为正确。
(2)简化复杂的判断条件
对于复杂的判断条件,可以通过 bool 值的设值来增加代码的可读性。比如定义这样一个判断:打印优秀学生的姓名,其中优秀学生满足的条件是:数学分数大于95分,语文分数大于92分并且体育达标,样例代码如下:
#include
using namespace std;
struct Student
{
string name;
double mathScore; //数学成绩
double literatureScore; //语文成绩
bool sportsFlag; //体育达标
};
int main()
{
Student st;
if (st.mathScore>95 && st.literatureScore>92 && st.sportsFlag)
{
printf("name = %s",st.name.c_str());
}
//使用 bool 变量 excellentStudentFlag,提高了代码的可读性,比增加注释更好
bool excellentStudentFlag = st.mathScore > 95 && st.literatureScore > 92 && st.sportsFlag;
if (excellentStudentFlag)
{
printf("name = %s", st.name.c_str());
}
return 0;
}
(3)花括号的使用
在 if-else 语句中,如果只有一条语句需要执行,可以省略花括号。但是,为了代码的可读性和防止出错的可能性,建议在 if-else 语句中始终使用花括号。这样可以方便后续代码的维护和修改。
(4)避免嵌套过深
嵌套过深的 if-else 语句会使代码难以阅读和维护。如果需要使用多个条件判断,可以考虑使用 switch-case 语句或者使用多态设计模式。
(5)考虑 if-else 的性能影响
if-else 语句是顺序执行,一直执行到判断为真的条件才会停止。在涉及大量数据处理的程序中,可能会对程序的性能产生影响,所以在性能要求较高的场景中,考虑使用其他更高效的控制语句或者算法,可以提高程序的运行效率。
switch 语句用于根据整型表达式的值在多个代码段中进行选择。
switch 语句基本语法如下:
switch (expression) {
case value1:
// 代码块1
break;
case value2:
// 代码块2
break;
...
default:
// 默认代码块
}
switch 语句使程序根据 expression 的值转移到其语句正文中的一个标记语句( case 语句或者 default 语句)。expression 必须是整数型或明确转换为整数型的类类型(注意:float 与 double 类型不能隐式地转换为整数型,因此它们不能被用作 switch 的表达式)。 switch 语句在处理多个条件时非常有用(性能也非常高,会精准命中到具体的 case 语句或者 default 语句中),可以替代多个嵌套的 if-else 语句,使代码更加简洁和易读。
(1)default 语句的位置
各个标记语句分支(case 语句或者 default 语句)出现的次序可以任意,通常将 default 语句放在最后。
(2)break 的使用
执行完一个 case 语句后,若无 break 语句,还将接着执行其后的分支中的语句序列。例如:
#include
using namespace std;
int main()
{
int val = 1;
switch (val)
{
case 0:
{
printf("0\n"); //switch 是直接命中到对应分支,所以这一句不会被执行
}
case 1:
{
printf("1\n"); //该分支被命中,这句会被执行
}
case 2:
{
printf("2\n"); //上一个分支没有 break ,所以这一句被执行
break;
}
case 3:
{
printf("3\n"); //上一个分支有 break ,所以本句不会被执行
break;
}
default:
break;
}
return 0;
}
上面代码的输出为:
1
2
C++ 提供了以下几种基础的循环类型:while 循环、do-while 循环、for 循环以及嵌套循环。
在 STL 编程中,C++ 提供了 for_each 循环(需引入头文件 #include
)。
C++11 标准提供了基于范围的 for 循环,让循环的编码与维护变得更加简便。
在程序执行到 while 语句时,首先判断循环条件中表达式的值,当表达式的值为假( 0 、false 或者空指针),则直接跳过循环体语句,执行 while 循环的下一条语句。
当表达式的值为真时,循环体语句的代码将被执行。每次执行完循环体语句后,循环条件中表达式会再次被判断,如果表达式的值仍然为真,循环将继续执行。否则当表达式的值为假,循环终止,进入 while 循环的下一条语句。
如下为语法格式:
while( 循环条件 ){
循环体语句
}
while 循环的关键点是循环可能一次都不会执行。当循环条件中表达式的值为假时,会跳过循环体语句,直接执行紧接着 while 循环的下一条语句。
break 语句以及 continue 语句用于 while 循环的控制。(除此之外还有 goto 语句,但是非常不建议在程序中使用该语句)
break 语句:当 break 语句出现在 while 循环的循环体语句时,循环会立即终止,且程序流将继续执行紧接着 while 循环的下一条语句。
continue 语句:当 continue 语句出现在 while 循环的循环体语句时,会跳过当前循环中的代码,强制开始下一次循环判断,判断结果为真则执行循环。
(1)循环条件的判断
表达式的值为假的条件是 0 、false 或者空指针,也就是说 while (-1) 也是会进入循环的。
(2)警惕无限循环
如果循环条件始终为真值,则 while 循环将会无限循环下去。
(3)作用域
每单次循环结束,循环体内的局部变量都被释放,下一次循环重新进入循环体,里边的全部局部变量都会重新定义。
do-while 循环的语法格式如下:
do
{
循环体语句
}
while( 循环条件 )
在 do-while 循环中,循环体语句至少执行一次,然后检查条件表达式。如果条件表达式为真,则继续执行代码块,并重复此过程。如果条件表达式为假,则退出循环。
除了循环体语句至少执行一次
这个特征点, do-while 循环的其他特性以及使用的注意点与上面的 while 循环相同。
for 循环用于重复程序的一部分几次(或多次)。其最常应用于固定次数的循环。
针对无限循环,for(;;)
与 while(true)
都可以实现该功能,不过从效率上看,while(true)
每次循环要判断循环条件, 而 for(;;)
循环没有判断,理论上会节省时间。
如下为语法格式:
for(初始化语句; 判断条件语句; 条件表达式语句){
循环体语句
}
for 循环初始值可以有多条初始化语句,但要求类型一样,并且中间用逗号隔开。循环变量的迭代也可以有多条变量迭代语句,中间用逗号隔开。如:for(i=0,j=0; j< num; i++,j+=10)
break 语句以及 continue 语句用于 for 循环的控制。(除此之外还有 goto 语句,但是非常不建议在程序中使用该语句)
break 语句:当 break 语句出现在 for 循环的循环体语句时,循环会立即终止,且程序流将继续执行紧接着 for 循环的下一条语句。
continue 语句:当 continue 语句出现在 for 循环的循环体语句时,会跳过当前循环中的代码,强制开始下一次循环判断,判断结果为真则执行循环。
(1)检查条件表达式,防止进入无限循环
for 循环的条件表达式用于确定循环何时继续或终止。确保条件表达式在每次迭代时都进行适当的更新,从而可以在完成期待循环次数时,可以结束循环。
(2)作用域
在 C++ 标准中,for 循环中声明的变量将在 for 循环结束后超出范围。 例如:
for (int i = 0; i < 2; i++)
{
printf("i = %d\n",i);
}
printf("i = %d\n", i); //错误: 这里的 i 已经超出 for 循环作用域
(3)for 循环执行顺序
针对 for 循环的语法结构:
for(初始化语句; 判断条件语句; 条件表达式语句){
循环体语句
}
首先执行初始化语句,该语句在整个 for 循环中仅执行一次。接下来执行判断条件语句,如果判断条件语句返回是真,则执行循环体语句。最后执行条件表达式语句,如此循环。样例代码如下:
#include
using namespace std;
int main()
{
for (int i = 0;printf("i < 2\n"), i < 2; i++, printf("i++\n"))
{
printf("i = %d\n",i);
}
return 0;
}
上面代码的输出为:
i < 2
i = 0
i++
i < 2
i = 1
i++
i < 2
从 for 循环执行顺序可知,条件表达式语句 i++ 与 ++i 的效果是一样的。
for_each 是 C++ 标准库中的一个算法,用于对容器中的每个元素执行指定的操作。它接受两个迭代器,表示要处理的范围,同时需要传入一个可调用对象(如函数、函数对象或 lambda 表达式),这个可调用对象定义了对每个元素执行的操作。for_each 主要用于遍历容器,如 vector 、 list 、set 等。
如下为语法格式:
for_each(开始迭代器, 结束迭代器, 可调用对象);
开始迭代器和结束迭代器定义了要处理的元素范围。
可调用对象(如函数、函数对象或 lambda 表达式)定义了对每个元素执行的操作。注意其接受容器中元素的引用作为参数。
for_each 循环提供了简洁的方式来遍历容器中的每个元素,并对每个元素执行特定的操作。它避免了编写显式的循环结构,使代码更加简洁和易读。
样例代码如下:
#include
#include
#include
using namespace std;
int main()
{
vector<int> vals = { 1,2,3,4,5,6 };
for_each(vals.begin(), vals.end(), [](int& val)
{
printf("%d ", val);
});
printf("\n");
return 0;
}
上面代码的输出为:
1 2 3 4 5 6
样例代码如下:
#include
#include
#include
using namespace std;
void printVal(int& val)
{
printf("%d ", val);
}
int main()
{
vector<int> vals = { 1,2,3,4,5,6 };
for_each(vals.begin(), vals.end(), printVal);
printf("\n");
return 0;
}
上面代码的输出为:
1 2 3 4 5 6
样例代码如下:
#include
#include
#include
using namespace std;
class PrintValFunc
{
public:
void operator() (int& val)
{
printf("%d ", val);
}
};
int main()
{
vector<int> vals = { 1,2,3,4,5,6 };
PrintValFunc printVal;
for_each(vals.begin(), vals.end(), printVal);
printf("\n");
return 0;
}
上面代码的输出为:
1 2 3 4 5 6
注:该部分内容涉及到 C++17 新特性。
C++17 引入了并行算法头文件 ,其中包含并行版本的 for_each 循环算法。如下为语法格式:
for_each(执行策略对象,开始迭代器, 结束迭代器, 可调用对象);
执行策略对象用于设置并行执行方式。可选的执行策略有:
std::execution::seq:顺序执行(非并行)
std::execution::par:并行执行
std::execution::par_unseq:并行和向量化执行
样例代码如下:
#include
#include
#include
using namespace std;
int main()
{
vector<int> vals = { 1,2,3,4,5,6 };
for_each(execution::par, vals.begin(), vals.end(), [](int& val)
{
printf("%d ", val);
});
printf("\n");
return 0;
}
需要注意的是,使用并行算法需要考虑线程安全和数据依赖等问题。在并行处理中,需要确保操作的线程安全性,并避免出现数据竞争和依赖错误。
注:该部分内容涉及到 C++11 新特性。
基于范围的 for 循环( range-based for loop )是 C++11 引入的一种新特性,它提供了一种简洁的方式来遍历容器或数组中的元素。对于 C++ 的容器来说(如 vector 、 list 、set 等),上面章节提到的 for 循环以及 for_each 循环,都需要显示的给出循环范围的开头和结尾,而基于范围的 for 循环则不需要再传递容器的两端,循环会自动以容器为范围展开,直接对容器中的元素进行处理。
如下为语法格式:
for (元素类型 变量名 : 容器或数组) {
// 循环体
}
其中,元素类型是容器或数组中元素的类型,变量名是用于遍历元素的临时变量,容器或数组是要遍历的容器或数组。容器或数组也可以为表达式,只要其返回值是容器或数组即可。
样例代码如下:
#include
using namespace std;
int main()
{
int vals[6] = { 1,2,3,4,5,6 };
for (const auto& val : vals)
{
printf("%d ", val);
}
printf("\n");
return 0;
}
上面代码的输出为:
1 2 3 4 5 6
样例代码如下:
#include
#include
using namespace std;
int main()
{
vector<int> vals = { 1,2,3,4,5,6 };
for (const auto& val : vals)
{
printf("%d ", val);
}
printf("\n");
return 0;
}
上面代码的输出为:
1 2 3 4 5 6