流程控制

1. 流程结构概述

程序流程结构是指编程中用于组织和控制代码执行顺序的结构。通过流程结构,可以按照特定的逻辑和条件来控制代码的执行路径,从而实现不同的功能和逻辑控制。以下是常见的程序流程结构:

  1. 顺序结构(Sequence Structure):按照代码编写顺序从上到下一行接一行地依次执行。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include <stdio.h>
    #include <stdbool.h>
    int main()
    {
    bool flag = true;
    flag = !flag;
    printf("flag = %d\n", flag);
    flag = !flag;
    printf("flag = %d\n", flag);
    return 0;
    }

    通过上面的示例代码可以看到,顺序结构的逻辑非常简单,下文就不再进行赘述。

  2. 选择结构(Selection/Decision Structure):根据给定的条件选择性地执行不同的代码块。

  3. 循环结构(Iteration/Loop Structure):循环执行一段代码,直到满足特定的条件为止。

  4. 跳转结构(Jump Structure):用于在代码执行过程中跳转到特定的位置,改变代码执行的流程。

这些程序流程结构可以根据实际需求嵌套和组合使用,以实现复杂的逻辑控制和算法实现。编程语言提供了对应的语法和关键字来支持这些流程结构的使用。具体的语法和用法可能会因编程语言而异,因此在编写代码时应参考相应的语言文档和规范。

2. 选择结构

2.1 if 语句

if语句是一种常见的选择结构,用于根据给定的条件选择性地执行不同的代码块。if语句根据条件的真假来确定执行哪个代码块。

if 语句的一般语法结构如下:

1
2
3
4
if (condition) 
{
// 当条件满足时执行的代码块
}

其中,condition是一个布尔表达式,当条件为真时,执行大括号{}内的代码块。如果条件为假,则跳过整个代码块,继续执行后续的代码。

示例程序如下:

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
int main()
{
int age1 = 11;
int age2 = 19;
if (age1 > age2)
{
printf("age1 的年龄比较大, age1 = %d\n", age1);
}
return 0;
}

布尔表达式age1 > age2不成立,所以第 8 行的输出是不会执行的。

2.2 if…else 语句

if 语句也可以与 else 结合使用,来处理条件为假时的情况,即执行不同的代码块。下面是if-else语句的语法示例:

1
2
3
4
5
6
7
8
if (condition) 
{
// 当条件满足时执行的代码块
}
else
{
// 当条件不满足时执行的代码块
}

示例程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
int main()
{
int age1;
int age2 = 18;
printf("请输入你的年龄:\n");
scanf("%d", &age1);
if (age1 >= age2)
{
printf("brother, 你是一个成年人, age1 = %d\n", age1);
}
else
{
printf("baby, 你是一个未成年人, age1 = %d\n", age1);
}
return 0;
}

上面的代码要求我们通过键盘输入一个年龄,程序根据我们的输入就能判断这个年龄属于成年人还是未成年人:

1
2
3
4
5
6
7
8
// 第一次执行
请输入你的年龄:
33
brother, 你是一个成年人, age1 = 33
// 第二处执行
请输入你的年龄:
10
baby, 你是一个未成年人, age1 = 10

我们在程序中输入了不同的数据,程序对布尔表达式的结果继续了判断,最终执行了不同的代码分支。

2.3 if…else if…else 语句

在C语言中,如果想要进行两个及以上的条件判断,使用if-else结构是无法满足需求的,此时可使用if-else if-else,该结构的语法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if (condition1) 
{
// 当条件1为真时执行的代码块
}
else if (condition2)
{
// 当条件2为真时执行的代码块
}
else if (condition3)
{
// 当条件3为真时执行的代码块
}
...
else
{
// 当所有条件都不满足时执行的代码块
}

在C语言中,ifelse if后面的条件表达式用圆括号括起来,并以大括号包围代码块:每个条件之间使用else if进行连接,else if的数量可以是 N 个,最后的else如果不需要可以忽略。

在使用以上语法进行条件判断的时候务必注意一个问题:这些条件语句之间是互斥关系,如果其中一个条件判断为真,就不会再对其他条件进行判断了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 版本1
#include <stdio.h>
int main()
{
int score;
char grade;
printf("请输入你考试成绩:\n");
scanf("%d", &score);
if (score >= 90)
{
grade = 'A';
}
else if (score >= 80)
{
grade = 'B';
}
else if (score >= 70)
{
grade = 'C';
}
else
{
grade = 'D';
}

printf("你的成绩等级是:%c\n", grade);
return 0;
}

在上面的示例程序中接收一个分数输入,然后根据制定的规则对分数进行等级划分,执行的结果如下:

1
2
3
请输入你考试成绩:
88
你的成绩等级是:B

如果对上面的条件判断稍微做一些手脚,那么得到的结果就完全不一样了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 版本2
#include <stdio.h>
int main()
{
int score;
char grade;
printf("请输入你考试成绩:\n");
scanf("%d", &score);
if (score >= 90)
{
grade = 'A';
}
if (score >= 80)
{
grade = 'B';
}
if (score >= 70)
{
grade = 'C';
}
else
{
grade = 'D';
}

printf("你的成绩等级是:%c\n", grade);
return 0;
}

执行程序,输入相同的数据,得到的结果如下:

1
2
3
请输入你考试成绩:
88
你的成绩等级是:C

在上面两段程序中,使用同样的等级判断标准,同样的分数,但是得到的等级却不一样,原因就在于我们在程序中的判断方式发生了变化,第二段程序的判断逻辑是有问题的。

  • if...else if...else...if...else 这是一个完整的结构,结构中的所有条件都是互斥的,一个条件为真之后,不会再对其他条件进行判断
  • ifif...elseif...else if...else 这是三个独立的判断结构,独立的判断结构之间是不互斥的
    • 在版本1中,判断结构只有一组,而在版本2中判断结构就变成多组了
    • 版本2中会先执行第 15 行代码,再执行第 19 行,发生了数据覆盖

2.4 三目运算符

三目运算符(也称为条件运算符)是一种简洁的条件表达式。它可以在一行代码中根据条件的真假返回不同的值。

一般来说,三目运算符的语法如下:

1
condition ? expression1 : expression2

其中,condition是一个布尔表达式,如果为真,则返回expression1的值;如果为假,则返回expression2的值。

以下是一个示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
int main()
{
int a = 10;
int b = 20;
int max;
// 方式1
if (a > b)
{
max = a;
}
else
{
max = b;
}
printf("max = %d\n", max);

// 方式2
a = 789;
b = 345;
max = a > b ? a : b;
printf("max = %d\n", max);
return 0;
}

上面代码中通过两种方式对连个整数进行比较,并求出最大值,结果如下:

1
2
max = 20
max = 789

由此可见,使用三目运算符能够使程序更加精简,但可读性也会有所降低。

2.5 switch 语句

switch语句是一种多分支选择结构,用于根据不同的条件值选择性地执行不同的代码块。它提供了一种比使用多个if...else if...else语句更清晰和简洁的方法。

一般来说,switch语句的语法结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
switch (expression) 
{
case value1:
// 当expression的值等于value1时执行的代码块
break;
case value2:
// 当expression的值等于value2时执行的代码块
break;
case value3:
// 当expression的值等于value3时执行的代码块
break;
...
default:
// 当expression的值与所有case都不匹配时执行的代码块
break;
}

在这个结构中,expression是一个表达式,它的值将与每个case语句后的value进行比较。如果expression的值与某个value相等,就执行对应的代码块,并在代码块结束后使用break语句跳出switch语句。如果没有匹配到任何的case,就会执行default后的代码块。

以下是一个示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <stdio.h>
int main()
{
int day;
printf("请输入数字: \n");
scanf("%d", &day);
switch (day)
{
case 1:
printf("星期一\n");
break;
case 2:
printf("星期二\n");
break;
case 3:
printf("星期三\n");
break;
case 4:
printf("星期四\n");
break;
case 5:
printf("星期五\n");
break;
case 6:
case 7:
printf("周末\n");
break;
default:
printf("无效的日期\n");
break;
}
return 0;
}

对程序进行测试会得到以下输出:

1
2
3
请输入数字:
6
周末

根据day的值,选择不同的代码块进行执行。如果day的值为6,打印出的就是 “周末”。

需要注意的是,如果某个case的代码块执行完毕后没有使用break语句,将会继续执行后面的代码块(即”穿透”到下一个case)。这可以用来处理某些具有共同逻辑的情况,如上述示例中的周末情况。

另外,在C语言中,switch语句的条件有以下几个要求:

  1. 条件表达式必须是一个整型值,可以是整数、字符或枚举类型。在C语言中,浮点数、字符串或其他数据类型不能作为 switch 语句的条件。
  2. case后面的值必须是一个常量表达式,不能使用变量或其他表达式。
  3. 每个 case 语句结束后必须使用break语句来跳出整个 switch 语句块,否则将会”穿透”到后续的 case 执行。

3. 循环结构

3.1 for 语句

在C语言中,for语句是一种循环语句,用于重复执行一段代码块,直到指定的循环条件不再满足。for语句通常在已知循环次数的情况下使用。

一般来说,for语句的语法结构如下:

1
2
3
4
for (initialization; condition; increment/decrement) 
{
// 循环执行的代码块
}
  • initialization:在循环开始前执行的初始化代码,通常用于初始化循环变量;
  • condition:循环条件,只有当条件满足时循环会继续执行;
  • increment/decrement:在每次循环迭代完成后执行的增量/减量操作,用于更新循环变量的值;

以下是一个示例:

1
2
3
4
5
6
7
8
9
#include <stdio.h>
int main()
{
for (int i = 1; i <= 5; i++)
{
printf("循环变量的值为:%d\n", i);
}
return 0;
}

代码输出的信息如下:

1
2
3
4
5
循环变量的值为:1
循环变量的值为:2
循环变量的值为:3
循环变量的值为:4
循环变量的值为:5

在上述示例中,for语句将循环变量i初始化为1,然后检查条件i <= 5是否满足。如果条件为真,则执行代码块,并在每次循环迭代完成后将i的值增加1。当i的值为6时,不再满足条件,循环终止。

for语句的循环条件可以是任何能够产生布尔值(真或假)的表达式。例如,可以使用比较运算符(如 <><=>===!=)来判断条件,也可以使用逻辑运算符(如&&||)进行复合条件判断。

需要注意的是,for循环中的初始化、条件和增量/减量操作都是可选的。如果省略了初始化或增量/减量操作,可以在循环外部定义和更新循环变量。如果省略了条件,则被认为永远为真,从而变成一个无限循环(死循环)。

在循环体内部,可以使用break语句跳出循环,提前结束循环的执行,或使用continue语句跳过当前迭代,继续下一次循环迭代。

for语句在C语言中经常用于迭代数组、列表和其他数据结构中的元素,以及执行指定次数的重复操作。

3.2 while 语句

在C语言中,while语句是一种循环语句,用于重复执行一段代码块,直到指定的循环条件不再满足。while语句通常用于未知循环次数的情况下。

一般来说,while语句的语法结构如下:

1
2
3
4
while (condition) 
{
// 循环执行的代码块
}

condition是循环条件,只有当条件满足时,循环会继续执行对应的代码块。

以下是一个示例:

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
int main()
{
int i = 1;
while (i <= 5)
{
printf("循环变量的值为:%d\n", i);
i++;
}
return 0;
}

程序输出的结果如下:

1
2
3
4
5
循环变量的值为:1
循环变量的值为:2
循环变量的值为:3
循环变量的值为:4
循环变量的值为:5

在上述示例中,while语句首先检查条件i <= 5是否满足。如果条件为真,则执行代码块中的语句,并在每次循环迭代完成后将i的值增加1。当i的值为6时,不再满足条件,循环终止。

需要注意的是,循环体内的代码块应该包含导致循环条件最终为假的操作,否则会导致无限循环。在循环体内部,可以使用break语句跳出循环,提前结束循环的执行,或使用continue语句跳过当前迭代,继续下一次循环迭代。

while语句适用于任何循环次数未知的情况,例如在读取数据时,可以使用while语句循环读取,直到满足某个终止条件为止。

3.3 do…while 语句

在C语言中,do...while语句是一种循环语句,用于至少执行一次代码块,并在每次执行后检查循环条件,如果条件满足,则继续执行循环。与while语句不同,do...while语句先执行代码块,再判断条件。

一般来说,do...while语句的语法结构如下:

1
2
3
4
do 
{
// 循环执行的代码块
} while (condition);

condition 是循环条件,当条件满足时,循环会继续执行对应的代码块。在每次执行代码块后,会检查condition的值。

以下是一个示例:

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
int main()
{
int i = 1;
do
{
printf("循环变量的值为:%d\n", i);
i++;
} while (i <= 5);
return 0;
}

程序输出的信息如下:

1
2
3
4
5
循环变量的值为:1
循环变量的值为:2
循环变量的值为:3
循环变量的值为:4
循环变量的值为:5

在上述示例中,do语句先执行代码块中的语句,然后再进行条件判断,即使条件不满足,也会至少执行一次代码块。condition的值为真时,继续执行代码块,直到条件为假时,循环终止。

需要注意的是,与whilefor循环不同,do...while循环中的代码块至少会执行一次,无论条件是否满足。如果在循环体内使用break语句提前结束循环,也会在第一次执行后跳出循环。

do...while语句适用于需要至少执行一次循环体的情况,然后根据条件决定是否继续执行循环。

3.4 嵌套循环

在C语言中,嵌套循环是指在一个循环内部再嵌套一个或多个循环。通过嵌套循环,可以实现对多维数据结构的遍历、组合问题的解决以及一些复杂的算法。嵌套循环的语法结构如下,此处使用 for 来给大家举例:

1
2
3
4
5
6
7
8
for (初始化语句1; 条件表达式1; 增量/减量操作1) 
{
for (初始化语句2; 条件表达式2; 增量/减量操作2)
{
// 嵌套循环体代码
}
// 外层循环体代码
}

也可以使用whiledo...while来实现嵌套循环,只需将相应的语法结构放置在另一个循环体中。

以下是一个示例,展示了一个简单的嵌套循环:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
int main()
{
// 外层循环
for (int i = 1; i <= 3; i++)
{
// 内层循环
for (int j = 1; j <= 3; j++)
{
printf("i = %d, j = %d\n", i, j);
}
}
return 0;
}

在上述示例中,外层循环执行3次,内层循环每次外层循环执行时都会执行3次。因此,总共会输出9对数字。程序输出的结果如下:

1
2
3
4
5
6
7
8
9
i = 1, j = 1
i = 1, j = 2
i = 1, j = 3
i = 2, j = 1
i = 2, j = 2
i = 2, j = 3
i = 3, j = 1
i = 3, j = 2
i = 3, j = 3

在嵌套循环中,内层循环的每次迭代都会完全执行完毕,然后外层循环再进行下一次迭代。可以根据具体问题的需求,在嵌套循环中进行条件判断、嵌套层级的控制、循环变量的更新等操作。

需要注意的是,嵌套循环的层数过多,循环次数过大可能会导致性能问题,因此在编写嵌套循环时应考虑算法的效率和优化。

关于嵌套循环,不仅仅局限于forfor之间的嵌套,forwhiledo…while之间都可以相互嵌套或者自我嵌套,大家举一反三,此处不再举例。

4. 跳转结构

在C语言中,跳转结构(Jump Statements)用于控制程序在特定条件下跳转到代码的其他位置。主要有以下几种跳转结构:

  1. break语句:用于跳出当前循环或switch语句。
  2. continue语句:用于结束当前迭代,跳到下一次迭代。
  3. goto语句:用于无条件跳转到程序中的指定标记处。

4.1 break

break语句被执行时,程序将跳出最内层的循环或switch语句的执行,并继续执行后续的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <stdio.h>
#include <stdbool.h>
int main()
{
int i = 0;
while (1)
{
i++;
printf("i = %d\n", i);

if (i == 3)
{
break;
}
}
printf("======================\n");
bool flag = false;
for (int m = 0; m < 10; m++)
{
printf("外层 m = %d\n", m);
for (int n = 0; n < 10; n++)
{
printf("内层 n = %d\n", n);
if (n == 5)
{
flag = true;
break;
}
}
if (flag == true)
{
break;
}
}
return 0;
}
  • 第 13 行:跳出 while 循环,程序开始执行第 16 行
  • 第 27 行:跳出第 21 行的内层 for 循环,程序开始执行第 30 行
  • 第 32 行:跳出第 18 行的外层 for 循环,程序开始执行第 35 行

4.2 continue

continue语句被执行时,程序将跳过当前迭代中剩余的代码,然后继续下一次迭代。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include<stdio.h>
int main()
{
int sum = 0;
for (int i = 1; i <= 10; i++)
{
if (i % 2 == 0)
{
continue;
}
sum += i;
}
printf("sum = %d\n", sum);
return 0;
}

程序输出的结果为:

1
sum = 25

很显然上面的程序是想求出10以内的奇数之和,即1+3+5+7+9=25,通过continue 完美跳过了所有的i为偶数的情况。

4.3 goto

goto语句是C语言中的一种跳转语句,它允许无条件地将程序控制转移到程序中的指定位置。goto语句的语法如下:

1
goto label;

其中,label是一个用户定义的标识符,它通常表示要跳转到的位置。标识符通常位于goto语句之后,并且位于冒号(:)之前。需要注意以下几点:

  • label必须是在当前函数内定义的标签。标签的命名规则与变量的命名规则相同,由字母、数字和下划线组成,但标签不能与C语言的关键字冲突。
  • goto语句通常用于跳转到同一函数内的某个位置,但也可以跳转到同一文件中的其他函数内的标签(不推荐)。
  • goto语句应慎用,因为过多或滥用goto语句可能会导致代码逻辑混乱、难以维护和阅读。通常情况下,可以使用循环或条件语句等结构化的控制流语句来代替goto语句。

以下是一个简单的示例,展示了goto语句的用法:

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
int main() {
int num = 1;
start:
printf("当前的数字是 %d\n", num);
num++;
if (num <= 5) {
goto start;
}
printf("结束");
return 0;
}

程序输出的结果如下:

1
2
3
4
5
6
当前的数字是 1
当前的数字是 2
当前的数字是 3
当前的数字是 4
当前的数字是 5
结束

在上述示例中,使用goto语句创建了一个简单的循环,循环打印数字1到5,并在最后输出”结束”。
但请注意,以上程序仅作为示例。通常情况下,可以使用更结构化的控制流语句(例如for循环或while循环)来实现类似的功能,不要使用goto,不要使用goto,不要使用goto