突破编程_C++_基础教程(选择与循环)

1 选择

C++ 的选择逻辑包含 if-else 语句与 switch 语句,为程序提供了一种有条件地执行代码块的方式。

1.1 if-else 语句

C++编程中,if-else 语句用于测试条件。C++ 包含如下类型的 if-else 语句:if 语句、if-else 语句、嵌套 if 语句以及 if-else-if 梯形语句。

1.1.1 if-else 语句基本语法

if-else 语句基本语法如下:

if( condition )
{
	if-branch 
}
else if( condition )
{
	else-if-branch 
}
else
{
	else-branch 
}

if-else 语句控制条件分支逻辑:当 condition 计算结果为非零值时,会执行 if-branch 语句。否则,如果存在 else ,将执行 else-branch 语句。

1.1.2 if-else 语句使用的注意点

(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 语句是顺序执行,一直执行到判断为真的条件才会停止。在涉及大量数据处理的程序中,可能会对程序的性能产生影响,所以在性能要求较高的场景中,考虑使用其他更高效的控制语句或者算法,可以提高程序的运行效率。

1.2 switch 语句

switch 语句用于根据整型表达式的值在多个代码段中进行选择。

1.2.1 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.2.2 switch 语句使用的注意点

(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

2 循环

C++ 提供了以下几种基础的循环类型:while 循环、do-while 循环、for 循环以及嵌套循环。
在 STL 编程中,C++ 提供了 for_each 循环(需引入头文件 #include )。
C++11 标准提供了基于范围的 for 循环,让循环的编码与维护变得更加简便。

2.1 while 循环

在程序执行到 while 语句时,首先判断循环条件中表达式的值,当表达式的值为假( 0 、false 或者空指针),则直接跳过循环体语句,执行 while 循环的下一条语句。
当表达式的值为真时,循环体语句的代码将被执行。每次执行完循环体语句后,循环条件中表达式会再次被判断,如果表达式的值仍然为真,循环将继续执行。否则当表达式的值为假,循环终止,进入 while 循环的下一条语句。

2.1.1 while 循环的语法格式

如下为语法格式:

while( 循环条件 ){
    循环体语句
}

while 循环的关键点是循环可能一次都不会执行。当循环条件中表达式的值为假时,会跳过循环体语句,直接执行紧接着 while 循环的下一条语句。

2.1.2 while 循环的控制

break 语句以及 continue 语句用于 while 循环的控制。(除此之外还有 goto 语句,但是非常不建议在程序中使用该语句)
break 语句:当 break 语句出现在 while 循环的循环体语句时,循环会立即终止,且程序流将继续执行紧接着 while 循环的下一条语句。
continue 语句:当 continue 语句出现在 while 循环的循环体语句时,会跳过当前循环中的代码,强制开始下一次循环判断,判断结果为真则执行循环。

2.1.3 while 循环使用的注意点

(1)循环条件的判断
表达式的值为假的条件是 0 、false 或者空指针,也就是说 while (-1) 也是会进入循环的。
(2)警惕无限循环
如果循环条件始终为真值,则 while 循环将会无限循环下去。
(3)作用域
每单次循环结束,循环体内的局部变量都被释放,下一次循环重新进入循环体,里边的全部局部变量都会重新定义。

2.2 do-while 循环

do-while 循环的语法格式如下:

do
{
	循环体语句
}
while( 循环条件 )

在 do-while 循环中,循环体语句至少执行一次,然后检查条件表达式。如果条件表达式为真,则继续执行代码块,并重复此过程。如果条件表达式为假,则退出循环。
除了循环体语句至少执行一次这个特征点, do-while 循环的其他特性以及使用的注意点与上面的 while 循环相同。

2.3 for 循环

for 循环用于重复程序的一部分几次(或多次)。其最常应用于固定次数的循环。
针对无限循环,for(;;)while(true) 都可以实现该功能,不过从效率上看,while(true) 每次循环要判断循环条件, 而 for(;;) 循环没有判断,理论上会节省时间。

2.3.1 for 循环的语法格式

如下为语法格式:

for(初始化语句; 判断条件语句; 条件表达式语句){
    循环体语句
}

for 循环初始值可以有多条初始化语句,但要求类型一样,并且中间用逗号隔开。循环变量的迭代也可以有多条变量迭代语句,中间用逗号隔开。如:for(i=0,j=0; j< num; i++,j+=10)

2.3.2 for 循环的控制

break 语句以及 continue 语句用于 for 循环的控制。(除此之外还有 goto 语句,但是非常不建议在程序中使用该语句)
break 语句:当 break 语句出现在 for 循环的循环体语句时,循环会立即终止,且程序流将继续执行紧接着 for 循环的下一条语句。
continue 语句:当 continue 语句出现在 for 循环的循环体语句时,会跳过当前循环中的代码,强制开始下一次循环判断,判断结果为真则执行循环。

2.3.3 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 的效果是一样的。

2.4 for_each 循环

for_each 是 C++ 标准库中的一个算法,用于对容器中的每个元素执行指定的操作。它接受两个迭代器,表示要处理的范围,同时需要传入一个可调用对象(如函数、函数对象或 lambda 表达式),这个可调用对象定义了对每个元素执行的操作。for_each 主要用于遍历容器,如 vector 、 list 、set 等。

2.4.1 for_each 循环语法结构

如下为语法格式:

for_each(开始迭代器, 结束迭代器, 可调用对象);

开始迭代器和结束迭代器定义了要处理的元素范围。
可调用对象(如函数、函数对象或 lambda 表达式)定义了对每个元素执行的操作。注意其接受容器中元素的引用作为参数。
for_each 循环提供了简洁的方式来遍历容器中的每个元素,并对每个元素执行特定的操作。它避免了编写显式的循环结构,使代码更加简洁和易读。

2.4.2 for_each 循环使用 Lambda 表达式作为可调用对象

样例代码如下:

#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 

2.4.3 for_each 循环使用普通函数作为可调用对象

样例代码如下:

#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 

2.4.4 for_each 循环使用函数对象作为可调用对象

样例代码如下:

#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 

2.4.4 for_each 循环的并行功能

注:该部分内容涉及到 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;
}

需要注意的是,使用并行算法需要考虑线程安全和数据依赖等问题。在并行处理中,需要确保操作的线程安全性,并避免出现数据竞争和依赖错误。

2.5 基于范围的 for 循环

注:该部分内容涉及到 C++11 新特性。
基于范围的 for 循环( range-based for loop )是 C++11 引入的一种新特性,它提供了一种简洁的方式来遍历容器或数组中的元素。对于 C++ 的容器来说(如 vector 、 list 、set 等),上面章节提到的 for 循环以及 for_each 循环,都需要显示的给出循环范围的开头和结尾,而基于范围的 for 循环则不需要再传递容器的两端,循环会自动以容器为范围展开,直接对容器中的元素进行处理。

2.5.1 基于范围的 for 循环的语法格式

如下为语法格式:

for (元素类型 变量名 : 容器或数组) {  
    // 循环体  
}

其中,元素类型是容器或数组中元素的类型,变量名是用于遍历元素的临时变量,容器或数组是要遍历的容器或数组。容器或数组也可以为表达式,只要其返回值是容器或数组即可。

2.5.2 基于范围的 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 

2.5.3 基于范围的 for 循环用于容器

样例代码如下:

#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 

你可能感兴趣的:(突破编程_C++_基础教程,c++)