07. 流程控制
一、流程控制
流程控制就是用来控制程序运行中各语句执行顺序的语句。基本的流程结构为:顺序结构,分支结构(或称选择结构),循环结构。
- 顺序结构:程序自上到下执行,中间没有任何判断和跳转;
- 分支结构:根据条件,选择性的执行某段代码,有 if……else 和 switch……case 两种分支语句;
- 循环结构:根据循环条件,重复性的执行某段代码,有 while、do……while、for 三种循环语句;
二、顺序结构
顺序结构 是 C语言 程序默认的执行流程,按照代码的先后顺序,从上到下依次执行,中间没有任何的判断和跳转。
#include <stdio.h>
int main(void)
{
printf("你好,世界!\n");
printf("Hello world!\n");
return 0;
}
三、分支结构
选择语句 也被称为 分支语句,它通过给定的条件进行判断,从而决定执行两个或者多个分支中哪一只。因此,在编写选择语句之前,应该首先明确判断条件是什么,并确定判断结果为“真”或“假”时应分别执行什么样的操作/算法。在 C 语言中选择语句主要提供了两种,一个是 if 语句,另一个则是 switch 语句。
3.1、if语句
3.1.1、if语句的单分支结构
if(关系表达式)
{
语句体;
}
执行流程:
- 首先计算 关系表达式 的值
- 如果关系表达式的值为 真(非 0) 就 执行语句体
- 如果关系表达式的值为 假(0) 就 不执行语句体
- 继续执行后面的其它语句
#include <stdio.h>
int main(void)
{
int number;
printf("请输入一个数:");
scanf("%d",&number);
if (number > 10)
printf("你输入的数字比10大\n");
printf("你输入的数字是:%d\n",number);
return 0;
}
在语句体中,如果只有一句代码,大括号可以省略不写,建议不要省略;
if 结构是可以嵌套的;
3.1.2、if语句的双分支结构
if(关系表达式)
{
语句体1;
}
else
{
语句体2;
}
执行流程:
- 首先计算 关系表达式 的值
- 如果关系表达式的值为 真(非 0) 就执行 语句体 1
- 如果关系表达式的值为 假(0) 就执行 语句体 2
- 继续执行后面的其它语句
#include <stdio.h>
int main(void)
{
int number;
printf("请输入一个数:");
scanf("%d",&number);
if (number > 10)
printf("你输入的数字比10大\n");
else
printf("你输入的数字等于10或者比10小\n");
printf("你输入的数字是:%d\n",number);
return 0;
}
当使用 if 语句的双分支结构进行嵌套使用时,如果没有花括号,else 默认与最近的未匹配的 if 语句配对,除非最近的 if 被花括号括起来;
3.1.3、if语句的多分支结构
if(关系表达式1)
{
语句体1;
}
else if (关系表达式2)
{
语句体2;
}
……
else
{
语句体n+1;
}
执行流程:
- 首先计算 关系表达式 1 的值
- 如果为 真(非 0) 就执行 语句体 1;如果为 假(0) 就计算 关系表达式 2 的值
- 如果为 真(非 0) 就执行 语句体 2;如果为 假(0) 就计算 关系表达式 3 的值
- ……
- 如果 所有的关系表达式 结果都为 假(0),就执行 else 子句中的 语句体 n+1
- 继续执行其它语句
#include <stdio.h>
int main(void)
{
int number;
printf("请输入一个数:");
scanf("%d",&number);
if (number > 10)
printf("你输入的数字比10大\n");
else if(number < 10)
printf("你输入的数字比10小\n");
else
printf("你输入的数为10\n");
printf("你输入的数字是:%d\n",number);
return 0;
}
else 结构是可选的;
if-else if-else 结构中最多只会有一个语句体执行;
如果多个条件表达式之间是 “互斥” 关系,哪个判断和执行语句声明在上面还是下面,无所谓;
如果多个条件表达式之间有 “交集” 关系,需根据实际情况,考虑清除应该将哪个结构写在上面;
如果多个条件表达式之间有 “包含” 关系,通常情况下,需要 将范围小的声明在范围大的上面。否则,范围小的没机会执行;
3.2、switch语句
switch(整型表达式)
{
case 整型常量表达式1:
语句体1;
break;
case 整型常量表达式2:
语句体2;
break;
……
case 整型常量表达式n:
语句体n;
break;
default:
语句体n+1;
break;
}
执行流程:
- 首先计算 表达式 的值
- 依次和 case 后面的值 进行比较,如果 有对应的值,就会执行相应的语句, 在执行过程中,遇到 break 就会结束
- 如果 所有的 case 后面的值 和 表达式 的值都不匹配,就会执行 default 里面的语句体,然后结束整个 switch 语句
格式说明:
- 表达式:表达式的结果是 整型变量
- case:后面跟的是 要和 switch 中的表达式进行比较的常量表达式,它只能是 枚举常量、数值常量、字符常量、常变量 或 宏定义常量 的一种,且 case 给出的值不能重复
- break:表示中断,结束的意思,用来 结束 switch 语句,break 关键字是可选的
- default:表示 所有情况都不匹配的时候,就执行该处的内容,相当于 if……else 中的 else,default 结构是可选的,而且位置是灵活的;
如果在语句体中 没有写 break 关键字,可能会导致 case穿透现象;case穿透现象 的执行流程如下:首先还是会拿着小括号中表达式的值跟下面的每一个 case 进行匹配,如果匹配上了,就会执行相应的代码,如果此时发现了 break,那么结束整个 switch 语句。如果没有发现 break,那么程序会继续执行下一个 case 语句体,一直遇到 break 或者 右大括号为止;
#include <stdio.h>
int main(void)
{
int day;
printf("请输入一个星期数:");
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:
printf("你输入的是星期六\n");
break;
case 7:
printf("你输入的是星期天\n");
break;
default:
printf("你输入的星期数不对\n");
break;
}
return 0;
}
凡是可以使用 switch……case 的结构,都可以转换为 if……else 。反之,不成立;
分支结构,既可以使用 switch……case(同时,switch 中表达式的取值不多时)又可以使用 if……else 时,优先使用 switch……case;
四、循环结构
循环就是重复的做某件事情;它具有明确的开始和停止标志;一组被重复执行的语句称之为 循环体,能否继续执行,取决于 循环的终止条件。在 C 语言中循环分为 for循环、while循环、do..while循环;循环结构具有以下四个组成部分:
- 初始化部分(init_statement)
- 循环条件部分(test_exp)
- 循环体部分(body_statement)
- 迭代部分(alter_statement)
通常情况下,循环结构都是因为 ② 中循环条件返回 false;
4.1、for循环
for(①初始化条件;②循环条件;④迭代条件)
{
③循环体;
}
执行流程:
- 执行 初始化语句
- 执行 条件判断语句,看其结果是 真(非 0) 还是 假(0)
- 如果是 假(0),循环结束,继续执行后面的其它语句
- 如果是 真(非0),执行循环体语句
- 执行 条件控制语句
- 回到②继续执行 条件判断语句
#include <stdio.h>
int main(void)
{
int i;
for (i = 0; i < 10; i++)
{
printf("Hello world!\n");
}
return 0;
}
初始化语句作为循环的开始,只会执行一次;
如果判断条件为 真(非 0),则循环继续;如果判断语句为 假(0),则循环结束;
for 循环 中可以添加多个初始化条件、条件判断内容、条件控制语句,多条内容之间中间用逗号分隔;
4.2、while循环
①初始化条件;
while(②循环条件)
{
③循环体;
④迭代条件;
}
执行流程:
- 执行 初始化语句
- 执行 条件判断语句,看其结果是 真(非 0) 还是 假(0)
- 如果是 假(0),循环结束,继续执行后面的其它语句
- 如果是 真(非 0),执行循环体语句
- 执行 条件控制语句
- 回到 ② 继续执行 条件判断语句
#include <stdio.h>
int main(void)
{
int i;
while(i < 10)
{
printf("Hello world!\n");
i++;
}
return 0;
}
如果判断条件为 true,则循环继续;如果判断语句为 false,则循环结束;
for 循环和 while 循环可以相互转换的;
4.3、do...while循环
①初始化条件
do{
③循环体;
④迭代条件;
}while(②循环条件);
执行流程:
- 执行 初始化语句
- 执行 循环体语句
- 执行 条件控制语句
- 执行 条件判断语句,看其结果是 真(非 0) 还是 假(0)
- 如果是 假(0),循环结束,继续执行后面的其它语句
- 如果是 真(非0),执行循环体语句
- 执行 条件控制语句
- 回到 ② 继续执行 条件判断语句
#include <stdio.h>
int main(void)
{
int i;
do{
printf("Hello world!\n");
i++;
}while(i < 10);
return 0;
}
do...while 循环先执行后判断,即循环体至少执行一次;
4.4、无限循环
for 循环的无限循环:
for(;;)
{
循环体;
}
while 循环的无限循环:
while(1)
{
循环体;
}
do...while 循环的无限循环
do{
循环体;
} while(1);
4.5、嵌套循环
将一个循环结构 A 声明在另一个循环结构 B 的循环体,就构成了嵌套循环;
- 外层循环:循环结构 B,控制行数
- 内层循环:循环结构 A,控制列数
内层结构遍历一遍,相当于外层循环循环体执行一次;假设外层循环需要执行 m 次,内层循环需要执行 n 次。此时内层循环的循环体一共执行了 m*n 次;
#include <stdio.h>
int main(void)
{
int i,j;
for (i = 1; i <= 9; i++)
{
for (j = 1; j <= i; j++)
{
printf("%d * %d = %-5d",i,j,i*j);
}
printf("\n");
}
return 0;
}
五、跳转语句
5.1、break与continue的使用
break 的作用是 结束当前循环,后面不能直接写执行语句,默认跳出包裹此关键字最近的一层循环;执行完 break 语句后会直接执行循环后面的第 1 条语句,连更新部分也跳过。嵌套循环内层的 break 只会让程序跳出包含它的当前循环,要跳出外层循环还需要一个 break。
#include <stdio.h>
int main(void)
{
int i;
for (i = 0; i <= 5; i++)
{
if (i == 3)
break;
printf("%d\n",i);
}
return 0;
}
continue 的作用是 结束当次循环,后面不能直接写执行语句,默认结束包裹此关键字最近的循环的一次;对于 while 循环 和 do…while 循环,执行 continue 语句后的下一个行为是对循环的测试表达式求值;对于 for 循环,执行 continue 后的下一个行为是对更新表达式求值,然后是对循环测试表达式求值,
#include <stdio.h>
int main(void)
{
int i;
for (i = 0; i <= 5; i++)
{
if (i == 3)
continue;
printf("%d\n",i);
}
return 0;
}
#include <stdio.h>
int main(void)
{
int i = 0;
while(i < 10)
{
i++;
if (i == 3)
continue;
printf("%d\n",i);
}
return 0;
}
continue 语句只能配合循环语句使用,不能单独和 switch/if 使用;
break 除了可以用在循环中,还可以和 swtich 语句搭配使用;
5.2、goto语句
C 语言的 goto 语句可以无条件转移到程序中指定的行,goto 语句通常与条件语句配合使用,可用来实现条件转移,跳出循环体等功能。在 C 程序中,一般不主张使用 goto 语句,以免造成程序流程的混乱,使理解和调试程序都产生困难。它的格式如下:
goto 标签;
标签:语句;
标签:语句;
goto 标签;
其中,标签是一个有效的标识符。这个标识符加上一个 “:” 一起出现在函数内某处,执行 goto 语句后,程序将跳转到该标识符处并执行其后的语句。另外,标签需要与 goto 语句处于同一个函数中。
#include <stdio.h>
int main(void)
{
// FLAG是一个标识符
goto FLAG;
printf("hello world!\n");
FLAG:
printf("你好,世界!\n");
return 0;
}
#include <stdio.h>
int main(void)
{
int i = 0,j = 0;
for(i = 0; i < 10; i++){
if(i == 5){ goto FLAG; }
printf("i = %d\n",i);
}
for(j = 0; j < 10; j++){
FLAG:
printf("j = %d\n",j);
}
return 0;
}
#include <stdio.h>
int main(void)
{
// 相当于死循环
FLAG:
printf("hello world!\n");
goto FLAG;
return 0;
}