C++ 控制结构深入解析与实践指南
C++ 控制结构概述
在 C++ 编程中,控制结构起着至关重要的作用。它们允许程序员根据不同的条件来控制程序的执行流程,使得程序不仅仅是顺序执行的指令集合,而是能根据具体情况做出不同响应的灵活系统。C++ 主要包含三种类型的控制结构:顺序结构、选择结构和循环结构。
顺序结构是程序中最基本的执行方式,代码按照编写的先后顺序依次执行,就像我们日常按步骤完成一件事情一样,例如:
#include <iostream>
int main() {
std::cout << "第一步" << std::endl;
std::cout << "第二步" << std::endl;
std::cout << "第三步" << std::endl;
return 0;
}
在这个简单的示例中,程序会依次输出“第一步”“第二步”“第三步”。
然而,实际的编程场景往往需要程序根据不同条件做出不同的决策,这就引出了选择结构和循环结构。选择结构让程序能够根据条件判断结果选择执行不同的代码块,循环结构则允许重复执行一段代码,直到满足特定条件为止。
选择结构
if - else 语句
- 基本形式 if - else 语句是 C++ 中最常用的选择结构。它的基本形式为:
if (condition) {
// 如果 condition 为真,执行这里的代码
} else {
// 如果 condition 为假,执行这里的代码
}
例如,我们要判断一个数是否为正数:
#include <iostream>
int main() {
int num = 10;
if (num > 0) {
std::cout << num << " 是正数" << std::endl;
} else {
std::cout << num << " 不是正数" << std::endl;
}
return 0;
}
在这个例子中,num > 0
就是条件 condition
,当 num
的值大于 0 时,会输出“10 是正数”,否则输出“10 不是正数”。
- 嵌套 if - else if - else 语句可以嵌套使用,用于处理更复杂的条件判断。例如,我们要判断一个数是否在某个区间内:
#include <iostream>
int main() {
int num = 15;
if (num >= 10) {
if (num <= 20) {
std::cout << num << " 在 10 到 20 之间" << std::endl;
} else {
std::cout << num << " 大于 20" << std::endl;
}
} else {
std::cout << num << " 小于 10" << std::endl;
}
return 0;
}
这里外层 if
判断 num
是否大于等于 10,内层 if
在满足外层条件的基础上进一步判断 num
是否小于等于 20。
- if - else if - else 链
当有多个互斥条件需要判断时,可以使用
if - else if - else
链:
#include <iostream>
int main() {
int score = 85;
if (score >= 90) {
std::cout << "A 等级" << std::endl;
} else if (score >= 80) {
std::cout << "B 等级" << std::endl;
} else if (score >= 70) {
std::cout << "C 等级" << std::endl;
} else {
std::cout << "其他等级" << std::endl;
}
return 0;
}
这个例子根据 score
的值来判断对应的等级,依次检查每个条件,一旦某个条件满足,就执行相应的代码块,并且不会再检查后续的条件。
switch - case 语句
- 基本形式
switch - case
语句也是一种选择结构,它根据一个整型或枚举类型的表达式的值来选择执行不同的分支。其基本形式为:
switch (expression) {
case value1:
// 当 expression 的值等于 value1 时执行这里的代码
break;
case value2:
// 当 expression 的值等于 value2 时执行这里的代码
break;
default:
// 当 expression 的值与所有 case 的值都不匹配时执行这里的代码
}
例如,根据一个整数来输出对应的星期几:
#include <iostream>
int main() {
int day = 3;
switch (day) {
case 1:
std::cout << "星期一" << std::endl;
break;
case 2:
std::cout << "星期二" << std::endl;
break;
case 3:
std::cout << "星期三" << std::endl;
break;
case 4:
std::cout << "星期四" << std::endl;
break;
case 5:
std::cout << "星期五" << std::endl;
break;
case 6:
std::cout << "星期六" << std::endl;
break;
case 7:
std::cout << "星期日" << std::endl;
break;
default:
std::cout << "无效的输入" << std::endl;
}
return 0;
}
在这个例子中,switch
后的表达式 day
的值决定了执行哪个 case
分支。break
语句用于跳出 switch
语句,防止继续执行下一个 case
分支。
- 注意事项
case
后的常量表达式必须是整型或枚举类型,且值必须唯一。- 如果没有
break
语句,程序会从匹配的case
开始,依次执行后面所有case
分支的代码,直到遇到break
或者switch
结束。例如:
#include <iostream>
int main() {
int num = 2;
switch (num) {
case 1:
std::cout << "一" << std::endl;
case 2:
std::cout << "二" << std::endl;
case 3:
std::cout << "三" << std::endl;
default:
std::cout << "其他" << std::endl;
}
return 0;
}
在这个例子中,由于 num
为 2,匹配 case 2
,但因为没有 break
,会继续执行 case 3
和 default
的代码,最终输出“二”“三”“其他”。
循环结构
while 循环
- 基本形式
while
循环会在给定条件为真时,重复执行一段代码。其基本形式为:
while (condition) {
// 当 condition 为真时,执行这里的代码
}
例如,我们要计算 1 到 10 的累加和:
#include <iostream>
int main() {
int sum = 0;
int i = 1;
while (i <= 10) {
sum += i;
i++;
}
std::cout << "1 到 10 的累加和为:" << sum << std::endl;
return 0;
}
在这个例子中,while
循环的条件是 i <= 10
,只要 i
小于等于 10,就会执行循环体中的代码,每次循环 i
自增 1,直到 i
大于 10 时循环结束。
- 无限循环
如果
while
循环的条件始终为真,就会形成无限循环。例如:
#include <iostream>
int main() {
while (true) {
std::cout << "这是一个无限循环" << std::endl;
}
return 0;
}
这样的无限循环在实际编程中需要谨慎使用,通常需要在循环体内部添加某种条件来跳出循环,比如使用 break
语句。
do - while 循环
- 基本形式
do - while
循环与while
循环类似,但它会先执行一次循环体,然后再检查条件。其基本形式为:
do {
// 先执行这里的代码
} while (condition);
例如,我们要实现一个简单的猜数字游戏,玩家输入猜测的数字,直到猜对为止:
#include <iostream>
#include <cstdlib>
#include <ctime>
int main() {
srand(time(0));
int target = rand() % 100 + 1;
int guess;
do {
std::cout << "请猜一个 1 到 100 之间的数字:";
std::cin >> guess;
if (guess > target) {
std::cout << "猜大了" << std::endl;
} else if (guess < target) {
std::cout << "猜小了" << std::endl;
}
} while (guess != target);
std::cout << "恭喜你,猜对了!" << std::endl;
return 0;
}
在这个例子中,无论玩家第一次猜测的数字是否正确,都会先执行一次循环体,让玩家输入猜测值并进行判断,然后再根据条件决定是否继续循环。
- 与 while 循环的区别
while
循环是先判断条件再执行循环体,而do - while
循环是先执行循环体再判断条件。这意味着do - while
循环至少会执行一次循环体,而while
循环如果条件一开始就不满足,循环体一次都不会执行。
for 循环
- 基本形式
for
循环是一种功能强大且灵活的循环结构,常用于已知循环次数的情况。其基本形式为:
for (initialization; condition; increment) {
// 当 condition 为真时,执行这里的代码
}
例如,计算 1 到 100 的偶数和:
#include <iostream>
int main() {
int sum = 0;
for (int i = 2; i <= 100; i += 2) {
sum += i;
}
std::cout << "1 到 100 的偶数和为:" << sum << std::endl;
return 0;
}
在这个 for
循环中,initialization
部分 int i = 2
初始化循环变量 i
为 2;condition
部分 i <= 100
是循环条件,只要 i
小于等于 100 就继续循环;increment
部分 i += 2
每次循环结束后将 i
增加 2。
- 省略部分内容
for
循环的三个部分(initialization
、condition
、increment
)都可以省略,但分号不能省略。例如:
- 省略
initialization
:
int i = 1;
for (; i <= 5; i++) {
std::cout << i << " ";
}
这里在 for
循环外部已经初始化了 i
,所以 for
循环中省略了 initialization
部分。
- 省略
condition
:
for (int i = 1; ; i++) {
std::cout << i << " ";
if (i == 5) {
break;
}
}
省略 condition
相当于条件永远为真,形成无限循环,这里通过 break
语句在 i
等于 5 时跳出循环。
- 省略
increment
:
for (int i = 1; i <= 5;) {
std::cout << i << " ";
i++;
}
这里把 increment
的操作放到了循环体内部。
循环控制语句
break 语句
break
语句用于立即终止当前循环(while
、do - while
、for
)或 switch - case
语句,跳出其所在的代码块。例如,在一个寻找特定数字的循环中:
#include <iostream>
int main() {
int numbers[] = {10, 20, 30, 40, 50};
int target = 30;
for (int i = 0; i < 5; i++) {
if (numbers[i] == target) {
std::cout << "找到了目标数字 " << target << ",索引为 " << i << std::endl;
break;
}
}
return 0;
}
当在数组中找到目标数字 30
时,break
语句会立即终止 for
循环,不再继续查找后续元素。
continue 语句
continue
语句用于跳过当前循环体中剩余的代码,直接进入下一次循环。例如,我们要输出 1 到 10 中的奇数:
#include <iostream>
int main() {
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
continue;
}
std::cout << i << " ";
}
return 0;
}
当 i
是偶数时,continue
语句会跳过 std::cout << i << " ";
这行代码,直接进入下一次循环,从而只输出奇数。
goto 语句
goto
语句可以无条件地跳转到程序中指定的标签处。虽然 goto
语句在现代编程中不被提倡使用,因为它可能会使程序的逻辑变得混乱,但在某些特定情况下仍有其用途。例如:
#include <iostream>
int main() {
int i = 0;
start:
std::cout << i << " ";
i++;
if (i < 5) {
goto start;
}
return 0;
}
这里 goto start;
语句会跳转到 start:
标签处,形成一个简单的循环。然而,过度使用 goto
可能导致代码难以理解和维护,应尽量避免在复杂程序中使用。
控制结构的嵌套与组合
在实际编程中,控制结构常常会嵌套使用或组合使用,以实现复杂的逻辑。例如,我们可以用嵌套的 for
循环来打印一个乘法表:
#include <iostream>
int main() {
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= i; j++) {
std::cout << j << "×" << i << "=" << i * j << "\t";
}
std::cout << std::endl;
}
return 0;
}
这里外层 for
循环控制行数,内层 for
循环控制每行的乘法表达式数量,通过嵌套实现了乘法表的打印。
又如,我们可以结合 if - else
和循环结构来处理更复杂的业务逻辑。比如,在一个学生成绩管理系统中,我们要统计不同等级的学生人数:
#include <iostream>
int main() {
int scores[] = {85, 92, 78, 65, 98};
int countA = 0, countB = 0, countC = 0;
for (int i = 0; i < 5; i++) {
if (scores[i] >= 90) {
countA++;
} else if (scores[i] >= 80) {
countB++;
} else {
countC++;
}
}
std::cout << "A 等级人数:" << countA << std::endl;
std::cout << "B 等级人数:" << countB << std::endl;
std::cout << "C 等级人数:" << countC << std::endl;
return 0;
}
这里通过 for
循环遍历学生成绩数组,再结合 if - else
语句对每个成绩进行等级判断,并统计各等级的人数。
控制结构在面向对象编程中的应用
在 C++ 的面向对象编程中,控制结构同样起着重要作用。例如,在类的成员函数中,我们可以使用控制结构来实现不同的业务逻辑。假设我们有一个 Rectangle
类,用于表示矩形,有计算面积和判断是否为正方形的功能:
#include <iostream>
class Rectangle {
private:
int width;
int height;
public:
Rectangle(int w, int h) : width(w), height(h) {}
int getArea() {
return width * height;
}
bool isSquare() {
if (width == height) {
return true;
} else {
return false;
}
}
};
int main() {
Rectangle rect1(5, 10);
Rectangle rect2(5, 5);
std::cout << "rect1 的面积:" << rect1.getArea() << std::endl;
if (rect1.isSquare()) {
std::cout << "rect1 是正方形" << std::endl;
} else {
std::cout << "rect1 不是正方形" << std::endl;
}
std::cout << "rect2 的面积:" << rect2.getArea() << std::endl;
if (rect2.isSquare()) {
std::cout << "rect2 是正方形" << std::endl;
} else {
std::cout << "rect2 不是正方形" << std::endl;
}
return 0;
}
在 isSquare
成员函数中,使用了 if - else
语句来判断矩形是否为正方形。在 main
函数中,通过 if - else
语句根据 isSquare
的返回值输出相应信息。
再比如,在处理对象数组时,我们可以使用循环结构。假设我们有一个 Student
类,并且有一个学生数组,我们要统计所有学生的平均成绩:
#include <iostream>
class Student {
private:
std::string name;
int score;
public:
Student(const std::string& n, int s) : name(n), score(s) {}
int getScore() {
return score;
}
};
int main() {
Student students[] = {Student("Alice", 85), Student("Bob", 90), Student("Charlie", 78)};
int totalScore = 0;
for (int i = 0; i < 3; i++) {
totalScore += students[i].getScore();
}
double averageScore = static_cast<double>(totalScore) / 3;
std::cout << "学生的平均成绩为:" << averageScore << std::endl;
return 0;
}
这里通过 for
循环遍历 Student
对象数组,获取每个学生的成绩并累加,最后计算平均成绩。
控制结构与异常处理
在 C++ 中,异常处理也是程序控制流程的一部分。异常处理机制允许程序在遇到错误或异常情况时,改变正常的执行流程,跳转到专门的异常处理代码块。例如,我们在进行除法运算时,可能会遇到除数为 0 的情况,这时可以抛出异常并进行处理:
#include <iostream>
double divide(double a, double b) {
if (b == 0) {
throw "除数不能为 0";
}
return a / b;
}
int main() {
try {
double result = divide(10, 2);
std::cout << "10 / 2 的结果为:" << result << std::endl;
result = divide(5, 0);
std::cout << "5 / 0 的结果为:" << result << std::endl;
} catch (const char* msg) {
std::cout << "捕获到异常:" << msg << std::endl;
}
return 0;
}
在 divide
函数中,如果除数 b
为 0,就抛出一个字符串类型的异常。在 main
函数中,使用 try - catch
块来捕获并处理异常。当 divide(5, 0)
执行时,会抛出异常,程序跳转到 catch
块中执行,输出“捕获到异常:除数不能为 0”,而不会继续执行 std::cout << "5 / 0 的结果为:" << result << std::endl;
这行代码。
异常处理与控制结构相互配合,可以让程序在面对各种意外情况时,保持良好的健壮性和稳定性,确保程序能够按照预期的方式运行,避免因为错误而导致程序崩溃。
通过深入理解和灵活运用 C++ 的各种控制结构,程序员能够编写出逻辑清晰、功能强大且高效的程序,无论是简单的控制台应用,还是复杂的大型项目,控制结构都是实现程序业务逻辑的核心工具之一。在实际编程过程中,需要根据具体的需求和场景,合理选择和组合控制结构,以达到最佳的编程效果。同时,随着编程经验的积累,对控制结构的运用也会更加得心应手,能够编写出更加优雅和高效的代码。