前言
C语言的语句分可以分为五类:
- 表达式语句
- 函数调用语句
- 控制语句
- 复合语句
- 空语句
本章带来的正是控制语句,其是用于控制程序的执行流程,实现程序的各种结构方式,分为分支、循环、转向语句。
一、 分支语句
1.if语句
if语句的语法结构
if(表达式1)
语句1;
else if(表达式2)
语句2;
else
语句3;
在if语句中,如果表达式为真(0表示假 非0表示真),则执行对应语句。其后面不能执行两/多条语句,但是加上{ }(代码块)就可以执行。所以建议在所有的if后面都加上{ },避免出错。
如果想写age在18和30岁之间的表达式,写表达式(age >= 18 && age < 30)是正确的,但(18<=age<30)是错误的。虽然看上去跟上段代码的含义相同,其实执行的顺序是不同的。计算机会先执行18<=age,若果为真再去执行age<30。
悬空else
else总是和他最近的if进行匹配,所以写代码要规范,形成标准的代码风格,代码风格很重要会增加代码的可读性。
int main()
{
int a = 0;
int b = 2;
if (a == 1)
{
if (b == 2)
{
printf("hehe\n");
}
}
else
{
printf("haha\n");
}
return 0;
}
表达式中的等号
当判断常量和变量是否相等的时候,把常量放在左边是一个很好的习惯。
2. switch语句
switch语句也是一种分支语句,常用与多分支的场景。
switch语句的语法结构
switch(整形表达式)
{
case 整形常量表达式;//case后面要加空格
语句;
}
break
在switch语句中,没办法直接实现分支,搭配break使用才能实现真正的分支。break表示跳出,可以是把语句列表划分为不同的分支部分。
不是每一个case后面都要加break,要按需加,当case3、4、5执行同一条语句的时候,就不需要都加break。
default
如果表达的值与所有的case标签的值都不匹配时,程序并不会终止,也不会报错,因为这种情况在C语言中并不认为是个错误。但是如果你并不想忽略不匹配所有标签的表达式的值时,应该在语句列表中增加一条default语句。
当 switch 表达式的值并不匹配所有 case 标签的值时,这个 default 子句后面的语句就会执行。每个switch语句中只能出现一条default子句,它可以出现在语句列表的任何位置。在每个 switch 语句中都放一条default子句是个好习惯,甚至可以在后边再加一个 break。
嵌套调用
switch允许嵌套使用
二、循环语句
循环语句分为三类:
- while循环
- for循环
- do while循环
1.while循环
while 语法结构:
while(表达式)
循环语句;
//在屏幕上打印1-10的数字。
int main()
{
int i = 1;
while(i<=10)
{
printf("%d ", i);
i = i+1;
}
return 0;
}
while语句的执行流程
break在while循环中的作用
循环中只要遇到break直接永久终止循环。
continue在while循环中的作用
continue用于终止本次循环,而是直接跳转到while语句的判断部分,进行下一次循环的入口判断。
// 只打印数字字符,跳过其他字符
#include <stdio.h>
int main()
{
char ch = '\0';
// EOF是-1 end of file 文件结束标志
while ((ch = getchar()) != EOF)// 实现多组输入
{
if (ch < '0' || ch > '9')
continue;
putchar(ch);
}
return 0;
}
-
上述代码中 getchar() 是stdio.h中的库函数,它的作用是从stdin流(标准输入流)读入一个字符,返回类型为int型,为用户输入的ASCII码或EOF。
-
当使用getchar()函数的时候的数据传输过程为:键盘 —— 缓冲区——getchar函数。
-
缓冲区又称为缓存,它是内存空间的一部分。在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区。
-
putchar(),语法结构为 int putchar(int char) ,其功能是把参数 char 指定的一个无符号字符写入到标准输出 stdout 中。其输出可以是一个字符,可以是介于0~127之间的一个十进制整型数,也可以是用char定义好的一个字符型变量。
清理缓冲区
2.for循环
for 语法结构
//语法:
for(表达式1; 表达式2; 表达式3)
循环语句;
- 表达式1为初始化部分,用于初始化循环变量的。
- 表达式2为条件判断部分,用于判断循环时候终止。
- 表达式3为调整部分,用于循环条件的调整。
- 跟while循环相比,for循环很好的解决了初始化、条件判断部分、调整部分分离的情况,形式更优。
- 不可在 for 循环体内修改循环变量,防止 for 循环失去控制。
- 建议for语句的循环控制变量的取值采用前闭后开区间写法。
for语句的执行流程
for循环中的continue
coutinue在while循环里面是跳到判断部分,coutinue在for循环里面是跳到调整部分。
for循环省略初始化部分
当for循环省略初始化部分,容易导致某些错误。
- 如下所示代码,原意图打印100次hello,因省略初始化导致只打印了10次。
int i = 0;
int j = 0;
for(; i<10; i++)
{
for(; j<10; j++)
{
printf("hello\n");
}
}
for循环判断部分
如果把for循环的判断部分省略了,就意味着恒为真。
- 另外判断部分的表达式要正确的书写,分清
=
和==
的区别。
3.do while循环
do while语法结构
//语法:
do
循环语句;
while(表达式);
do while语句的执行流程
continue在do…while循环中的作用
coutinue在do…while循环里面,是跳到判断部分循环至少执行一次,使用的场景有限,所以不是经常使用。
三、控制语句练习
计算 n的阶乘
int main()
{
int n = 0;
scanf("%d", &n);
int ret = 1; //注意ret不能定义为0
for (int i = 1; i <=n ; i++)
{
ret *= i;
}
printf("%d", ret);
return 0;
}
计算 1!+2!+3!+……+10!
int main()
{
int ret = 1;
int sum = 0;
for (int i = 0; i <=10 ; i++)
{
ret *= i;
sum += ret;
}
printf("%d", sum);
return 0;
}
在一个有序数组中查找具体的某个数字n
int mid = (left + right) / 2;
这一段代码求平均值的方法并不好,因为有可能会出现left、right大小不会溢出,但是二者之和会溢出。改成int mid = left + (right - left) / 2
这种算法会更好一些且一定不会溢出。
编写代码,演示多个字符从两端移动,向中间汇聚
- 如果用sizeof求数组最右侧的元素下标,应该
int right = sizeof(arr1) / sizeof(arr1[0]) - 2;
先减去\0,再减1。最好用strlen
这个函数求字符串的长度,它只计算\0之前的长度。
编写代码实现,模拟用户登录情景,并且只能登录三次
猜数字游戏
四、goto语句
- C语言中提供了可以随意滥用的 goto语句和标记跳转的标号。
- 从理论上 goto语句是没有必要的,实践中没有goto语句也可以很容易的写出代码。
- 但是某些场合下goto语句还是用得着的,最常见的用法就是终止程序在某些深度嵌套的结构的处理过程。
- 值得注意的是goto语句不能实现跨函数跳转。
for(...)
for(...)
{
for(...)
{
if(disaster)
goto error;
}
}
…
error:
if(disaster)
// 处理错误情况
//跳出三层循环