语句与控制流
C语言语句分为以下五类:
-
表达式语句
-
函数调用语句
-
控制语句
-
复合语句
-
空语句
其中控制语句用于控制程序的执行流程,以实现程序的各种结构方式,它们由特定的语句定义符组成,C语言有九种控制语句。
分为三类:
-
条件判断语句也叫分支语句:if语句、switch语句;
-
循环执行语句:do while语句、while语句、for语句;
-
转向语句:break语句、goto语句、continue语句、return语句
语句与程序块
表达式(Expression)和语句(Statement)的概念在C语言中并没有明确的定义:
- 表达式可以看做一个计算的公式,往往由数据、变量、运算符等组成,例如
3*4+5
、a=c=d
等,表达式的结果必定是一个值; - 语句的范围更加广泛,不一定是计算,不一定有值,可以是某个操作、某个函数、选择结构、循环等。
1.空语句
C语言最简单的就是空语句,本身只包含一个分号,空语句本身不执行任何任务,纯粹消耗cpu时间,起到延时的作用。
2.表达式语句
C并不存在专门的“赋值语句“,那么它的赋值就是一种操作,和加法减法一样,在表达式内部进行
x = y + 3;
ch = getchar();
这实际上是表达式语句,不是赋值语句!
3.程序块
代码块就是位于一对花括号之内的可选的声明和语句列表
{
declatations;
statements;
}
代码块可以用于要求出现语句的地方,它允许你在语法要求只出现一条语句的地方使用多条语句。代码块还允许你把数据的声明非常靠近它所使用的地方
重点:
- 表达式必须有一个执行结果,这个结果必须是一个值,例如
3*4+5
的结果 17,a=c=d=10
的结果是 10,printf("hello")
的结果是 5(printf
的返回值是成功打印的字符的个数)。 - 以分号
;
结束的往往称为语句,而不是表达式,例如3*4+5;
、a=c=d;
等。
分支语句(选择结构)
if else语句
if 语句的形式为:
if(判断条件){
语句块
}
多个if else语句
形式如下:
f(判断条件1){
语句块1
} else if(判断条件2){
语句块2
}else if(判断条件3){
语句块3
}else if(判断条件m){
语句块m
}else{
语句块n
}
一旦遇到能够成立的判断条件,则不再执行其他的语句块,所以最终只能有一个语句块被执行
if语句的嵌套
if 语句也可以嵌套使用,例如:
#include <stdio.h>
int main()
{
int a, b;
printf("Input two numbers:");
scanf("%d %d", &a, &b);
if (a != b)
{ //!=表示不等于
if (a > b)
printf("a>b\n");
else
printf("a<b\n");
}
else
{
printf("a=b\n");
}
return 0;
}
运行结果:
Input two numbers:12 68
a<b
if 语句嵌套时,C语言规定,else 总是与它前面最近的 if 配对
例如:
if(a!=b) // ①
if(a>b) printf("a>b\n"); // ②
else printf("a<b\n"); // ③
③和②配对,而不是和①配对。
switch语句
switch 是另外一种选择结构的语句,用来代替简单的、拥有多个分枝的 if else 语句,基本格式如下:
switch(表达式){
case 整型数值1: 语句 1;
case 整型数值2: 语句 2;
......
case 整型数值n: 语句 n;
default: 语句 n+1;
}
执行过程是:
-
首先计算“表达式”的值,假设为 m。
-
从第一个 case 开始,比较“整型数值1”和 m,如果它们相等,就执行冒号后面的所有语句,也就是从“语句1”一直执行到“语句n+1”,而不管后面的 case 是否匹配成功。
-
如果“整型数值1”和 m 不相等,就跳过冒号后面的“语句1”,继续比较第二个 case、第三个 case……一旦发现和某个整型数值相等了,就会执行后面所有的语句。假设 m 和“整型数值5”相等,那么就会从“语句5”一直执行到“语句n+1”。
-
如果直到最后一个“整型数值n”都没有找到相等的值,那么就执行 default 后的“语句 n+1”。
switch 语句必须遵循下面的规则:
- switch 语句中的 expression 必须是一个整型或枚举类型,或者是一个 class 类型,其中 class 有一个单一的转换函数将其转换为整型或枚举类型。
- 在一个 switch 中可以有任意数量的 case 语句。每个 case 后跟一个要比较的值和一个冒号。
- case 的 constant-expression 必须与 switch 中的变量具有相同的数据类型,且必须是一个常量或字面量。
- 当被测试的变量等于 case 中的常量时,case 后跟的语句将被执行,直到遇到 break 语句为止。
- 当遇到 break 语句时,switch 终止,控制流将跳转到 switch 语句后的下一行。
- 不是每一个 case 都需要包含 break。如果 case 语句不包含 break,控制流将会 继续 后续的 case,直到遇到 break 为止。
- 一个 switch 语句可以有一个可选的 default case,出现在 switch 的结尾。default case 可用于在上面所有 case 都不为真时执行一个任务。default case 中的 break 语句不是必需的。
例子:
case 10: printf("..."); break; //正确
case 8+9: printf("..."); break; //正确
case 'A': printf("..."); break; //正确,字符和整数可以相互转换
case 'A'+19: printf("..."); break; //正确,字符和整数可以相互转换
case 9.5: printf("..."); break; //✘,不能为小数
case a: printf("..."); break; //✘,不能包含变量
case a+10: printf("..."); break; //✘,不能包含变量
总结:
- case 后面必须是一个整数,或者是结果为整数的表达式,但不能包含任何变量。
- default 不是必须的。当没有 default 时,如果所有 case 都匹配失败,那么就什么都不执行。
循环语句
while语句
形式为:
while(表达式){
语句块
}
do-while循环
形式为:
do{
语句块
}while(表达式);
do-while循环与while循环的不同在于:它会先执行“语句块”,然后再判断表达式是否为真,如果为真则继续循环;如果为假,则终止循环。因此,do-while 循环至少要执行一次“语句块”。
for 循环
形式为:
for(表达式1; 表达式2; 表达式3){
语句块
}
- 表达式1 会首先被执行,且只会执行一次。这一步允许您声明并初始化任何循环控制变量。您也可以不在这里写任何语句,只要有一个分号出现即可。
- 接下来,会判断 表达式2。如果为真,则执行循环主体。如果为假,则不执行循环主体,且控制流会跳转到紧接着 for 循环的下一条语句。
- 在执行完 for 循环主体后,控制流会跳回上面的表达式3语句。该语句允许您更新循环控制变量。该语句可以留空,只要在条件后有一个分号出现即可。
- 条件再次被判断。如果为真,则执行循环,这个过程会不断重复(循环主体,然后增加步值,再然后重新判断条件)。在条件变为假时,for 循环终止。
双重循环嵌套执行原理
重循环的嵌套说白了 就是for套for。
for循环来说,执行原理就是:外层循环表示行数;内层循环表示列数;外层变量换到内层,达到递增递减效果。
转向语句(跳转语句)
goto语句
goto 语句是一种无条件流程跳转语句,通常 goto 语句与 if 语句结合使用,当满足一定条件时,程序流程跳转到指定标号处,接着往下执行。
使用 goto 语句可能会造成程序层次不清晰,可读性差,故在实际编程中,应尽量少使用或避免使用 goto
语句。一般不使用
break语句
当执行到循环体中的 break 语句时,将终止 break 所在该层的循环,从该层循环体之后的语句开始继续执行。
break 的执行流程如下所示。
单重循环情况:选用 while 循环结构示意,do-while 循环、for 循环同样适用。
while (循环判断表达式)
{
...
if(条件表达式)
break;
循环体中break后的语句;
}
循环体后的第 1 条语句;
循环体后的第 2 条语句;
...
在循环体中,当满足一定条件执行到 break 语句时,终止 break 所在的该层循环,即“循环体中 break 后的语句”部分将不再被执行,程序执行流程转向从“循环结构后的第 1 条语句”处,开始继续往后执行。
双重循环情况:使用双重 for 循环嵌套结构示意,其他类型的循环嵌套组合同样适用。
for (;循环判断表达式1;)
{
...
for(;循环判断表达式2;)
{
...
if(条件表达式)
break;
内层循环体中break后的语句;
}
内层循环结构后的第1条语句; 内层循环结构后的第2条语句;
...
}
在内层循环中,当满足一定条件执行到 break 语句时,仅结束 break 所在内层循环的执行(在本轮外层循环中,“内层循环体中 break 后的语句”部分不再被执行),程序执行流程跳转到“内层循环结构后的第 1 条语句”所在的外层循环体处,开始继续执行。
continue语句
在循环体中设置 continue 语句,同样可以改变循环的执行流程,只不过它不像 break 那样结束整个循环体,而是仅结束本次循环体的执行,提前进入下一次循环。
for(初始表达式;循环判断表达式;增量表达式)
{
...
if(条件表达式)
continue;
循环体中continue后的所有语句;
}
当在上述 for 循环中执行到 continue 语句时,本次循环体的执行流程将跳过“循环体中 continue 后的所有语句”,接着执行“增量表达式”部分,然后执行“循环判断表达式”,即提前进入下一次循环的准备工作。