1. 简单语句
1.空语句
最简单的语句就是空语句,空语句中只含有一个单独的分号。在程序的某个地方如果语法上需要一条语句但是逻辑上不需要,此时可以使用空语句。因为空语句是一条语句,所以在任何允许使用语句的地方都可使用。因此某些看起来非法的分号可以认为是一条空语句。
ival = c1 + v2;; // 第2个分号表示一条多余的空语句
2.复合语句
复合语句是指用花括号括起来的语句序列,复合语句也被称为语句块。
int x = 10;
int y = 20;
// 复合语句块
{
int z = x + y;
cout << "在复合语句块内,z的值为:" << z << endl;
}
3.语句作用域
可以在if、switch、while 和 for 语句的控制结构内定义变量,定义在控制结构当中的变量只在结构的内部可见,语句结束后变量销毁。如果其它代码块需要访问该变量,则应该将变量定义在代码块的外部。
// 在 if 语句内定义变量
if (true) {
int x = 10;
cout << "在 if 语句内部,x 的值为:" << x << endl;
}
cout << "在 if 语句外部,x 的值为:" << x << endl; // 这里会产生错误
2. 条件语句
C++ 提供了两种按条件执行的语句。一种是if语句,根据条件决定控制流,另外一种是switch语句,计算一个整型表达式的值,然后根据这个值从几个执行路径中选择一条。
2.1 if语句
if语句的作用是判断一个指定的条件是否为真,根据判断结果决定是否执行下面的语句。if 语句包括两种形式:一种含有 else 分支,另一种没有 else 分支。
// 情形1
int number = 20;
if (number > 10) {
int x = 5;
cout << "在 if 语句内部,x 的值为:" << x << endl;
}
// 情形2
if (number > 10) {
cout << "数字大于10" << endl;
} else if (number > 5) {
cout << "数字大于5,但不大于10" << endl;
} else {
cout << "数字不大于5" << endl;
}
1.悬垂else
当一个 if 语句嵌套在另一个 if 语句内时,很可能 if 分支会多于 else 分支。那么怎么知道某个给定的 else 和那个 if 匹配呢?C++ 规定 else 与离它最近的尚未匹配的 if 匹配。
#include <iostream>
int main() {
int x = 10, y = 20;
// 悬空的 else:else 和离它最近的 if 匹配
if (x > 5)
if (y > 15)
std::cout << "Both x > 5 and y > 15\n";
else
std::cout << "y <= 15\n"; // 这个 else 匹配的是第二个 if (y > 15)
// 为了使 else 和第一个 if 匹配,使用大括号
if (x > 5) {
if (y > 15)
std::cout << "Both x > 5 and y > 15\n";
} else {
std::cout << "x <= 5\n"; // 现在这个 else 匹配的是第一个 if (x > 5)
}
return 0;
}
注意: 要想使 else 分支和外层的 if 语句匹配起来,可以在内层 if 语句的两端加上花括号,使其成为一个块。
2.2 switch语句
switch语句提供了一条便利的途径使得我们可以在若干固定的选项中做出选择。
#include <iostream>
using namespace std;
int main() {
int choice = 2;
switch (choice) {
case 1:
cout << "选择了1" << endl;
break;
case 2:
cout << "选择了2" << endl;
break;
case 3:
cout << "选择了3" << endl;
break;
default:
cout << "选择了其他值" << endl;
break;
}
return 0;
}
1.swich内部的控制流
如果某个 case 标签匹配成功,将从该标签开始往后顺序执行所有 case 分支,除非程序显式地中断了这一过程,否则直到 switch 的结尾处才会停下来。要想避免执行后续 case 分支的代码,可在下一个 case 标签之前有加一条break语句。
2.default标签
如果没有一个 case 标签能匹配上 switch 表达式的值,程序将执行default标签后面的语句。
3.switch内部的变量定义
如前所述,switch 的执行流程有可能会跨过某些 case 标签。如果程序跳转到某个特定的 case,则 switch 结构中该 case 标签之前的部分会被忽略掉。如果忽略掉的一部分代码中含有变量的定义怎么办?答案是该行为是非法行为,要避免。
3. 迭代语句
迭代语句通常被称为循环,它重复执行操作直到满足某个条件才会停下来。
3.1 while语句
当不确定到底要迭代多少次时使用 while 语句比较合适,此外当我们想在循环结束后访问循环控制内的变量使用 while 语句也比较合适。
int count = 0;
while (count < 5) {
cout << "计数器:" << count << endl;
count++;
}
cout << count << endl;
3.2 do while语句
do while语句和 while 语句非常相似,唯一的区别是 do while 语句先执行循环体后检查条件,不管条件的值如何都至少执行一次循环体。
int count = 0;
do {
cout << "计数器:" << count << endl;
count++;
} while (count < 5);
cout << "循环结束!" << endl;
3.3 传统for语句
1.语法格式
for 语句的语法形式是
for(init-statement; condition; expression)
statement;
和其他声明一样,init-statement 可以定义多个对象。但是 init-statement 只能有一条声明语句,因此所有变量的基础类型必须相同。for 语句头能省略掉 init-statement 、condition 和 expression 中的任何一个或者全部。
2.传统for循环的执行流程
#include <iostream>
int main() {
// 示例 1:简单的 for 循环,遍历0-4
std::cout << "简单的 for 循环:" << std::endl;
for (int i = 0; i < 5; i++) {
std::cout << "i = " << i << std::endl;
}
return 0;
}
3.4 范围for语句
1.语法格式
这种语句可以遍历容器或者其它序列的所有元素。范围for语句的语法形式是:
for(declaration:expression)
statement;
expression 表示的必须是一个序列,比如用花括号括起来的初始值列表、数组或 vector 容器,这些类型的共同点是拥有能返回迭代器的 begin 和 end 成员。
2.注意事项
默认情况下,范围 for 循环中的元素是按值传递的。这意味着每个循环中的元素是容器中元素的副本。如果你想修改容器中的元素,需要按引用传递。
std::vector<int> vec = {1, 2, 3, 4, 5};
for (int v : vec) {
v = v * 2; // 修改的是 v 的副本,vec 中的元素不会改变
}
std::vector<int> vec2 = {1, 2, 3, 4, 5};
for (int &v : vec2) {
v = v * 2; // 修改 vec 中的元素
}
4. 跳转语句
跳转语句中断当前的执行过程,C++ 语言提供了 4 种跳转语句:break、continue、goto 和 return语句。
4.1 break语句
break语句负责终止离它最近的 while、do while、for 或者 switch 语句,并从这些语句之后的第一条语句开始继续执行。break 语句只能出现在迭代语句或者 switch 语句内部,break 语句的作用范围仅限于最近的循环或者 switch 语句。
#include <iostream>
using namespace std;
int main() {
for (int i = 0; i < 5; i++) {
cout << "当前值为:" << i << endl;
if (i == 3) {
cout << "达到值为3,退出循环" << endl;
break; // 当 i 的值等于 3 时终止循环
}
}
cout << "循环结束!" << endl;
return 0;
}
4.2 continue语句
continue 语句终止最近的循环中的当前迭代并立即开始下一次迭代,如下所示:
#include <iostream>
using namespace std;
int main() {
for (int i = 0; i < 5; i++) {
if (i == 2) {
cout << "跳过 i = 2" << endl;
continue; // 当 i 的值为 2 时跳过当前迭代
}
cout << "当前值为:" << i << endl;
}
cout << "循环结束!" << endl;
return 0;
}
4.3 goto语句
goto 是一种在编程语言中用于无条件转移到程序中的标签处的语句。它可以将程序的控制直接转移到指定的标签处,但由于其导致代码变得难以理解和维护,因此通常被视为是一种不良的编程实践。如下所示:
#include <iostream>
using namespace std;
int main() {
int count = 0;
start:
cout << "计数器:" << count << endl;
count++;
if (count < 5) {
goto start; // 转移到标签 start 处
}
cout << "循环结束!" << endl;
return 0;
}
4.4 return语句
return 语句用于从函数中返回值,并可选择性地将一个值传递回调用函数处。在 C++ 中,函数可以返回一个值,也可以不返回值。
// 函数返回一个整数
int add(int a, int b) {
return a + b;
}
// 函数不返回任何值
void displayMessage() {
cout << "这是一个无返回值的函数" << endl;
// 在 void 函数中可以直接使用 return;,它表示结束函数执行,没有返回值
return;
}
5. try语句块和异常处理
异常是指存在于运行时的反常行为,这些行为超出了函数正常功能的范围。典型的异常包括失去数据库连接和遇到意外输入等。异常处理机制为程序中异常检测和异常处理这两部分的协作提供支持。
5.1 throw表达式
throw 表达式抛出一个异常,可以是任何类型的数据。在代码中,当出现错误情况时,你可以使用 throw 抛出一个异常,并通过 try - catch 块来捕获和处理这个异常。
#include <iostream>
using namespace std;
double division(int a, int b) {
if (b == 0) {
throw "除数为零异常"; // 抛出一个字符串异常
}
return static_cast<double>(a) / b;
}
int main() {
try {
cout << "开始计算:" << endl;
double result = division(10, 0); // 调用 division 函数
cout << "结果为:" << result << endl;
} catch (const char* error) { // 捕获字符串异常
cout << "捕获到异常: " << error << endl;
}
return 0;
}
5.2 标准异常
C++ 标准库提供了一组异常类,用于报告在标准库函数中可能发生的问题。它们提供了一种标准化的方式来处理错误情况,可以在用户编写的程序中使用它们来报告和处理异常。这些异常类分别定义在 4 个标准头文件中。
头文件 | 作用 |
---|---|
stdexcept | 这个头文件定义了一些标准异常类,它们是最常见的异常类之一 |
new | 这个头文件定义了与动态内存分配和管理相关的异常类 |
utility | 这个头文件定义了一些与 pair 和 tuple 相关的异常类 |
ios | 这个头文件定义了一些与输入/输出流相关的异常类 |