前言
文章细分了各个知识点,可在目录中快速跳转。
手机端用户在查看代码块时建议点击代码右上角放大查看,每一段代码均有完整注释。
C语言是结构化的程序设计语言,这里的结构指的是顺序结构、选择结构、循环结构这三种结构。其实我们如果仔细分析,我们日常所见的事情都可以拆分为这三种结构或者这三种结构的组合。其中顺序结构很简单,就是一条道,一路走到黑,因此我们下面主要来介绍C语言中对应选择结构和循环结构的语句。
一、分支语句(选择结构)
1. if语句
1.1 if
if(表达式)
语句
表达式成立(为真),则语句执行;
表达式不成立(为假),则语句不执行。
在C语言中,0为假,非0表示真,也就是表达式的结果如果是0,则语句不执行,表达式的结果如果不是0,则语句执行。
1.2 else
如果我们在 if 语句后追加 else 语句,则构成了一个if else语句。
逻辑是当 if 表达式为真执行if语句后,则不执行else对应的语句;当if表达式为假不执行时,则执行else对应语句。
我们通过一个实例来体会一下。
输入一个年龄,>= 18岁就输出:成年,否则就输出:未成年
#include <stdio.h>
int main()
{
int age = 0;
scanf("%d", &age);
if (age >= 18)
printf("成年\n");
else
printf("未成年\n");
return 0;
}
1.3 分支中包括多条语句
默认在 if 和 else 语句中默认都只控制⼀条语句,比如:
#include <stdio.h>
int main()
{
int age = 0;
scanf("%d", &age);
if (age >= 18)
printf("成年了\n");
printf("可以谈恋爱了\n");
return 0;
}
我们发现不管输入的age是否大于或等于18,对于 printf("可以谈恋爱了\n");
是独⽴存在的,不管if语句的条件的真假,都会被执行。那如果我们要if语句同时控制多条语句,怎么办呢?那就要使用 {} 将语句都括起来,这样就构成了一个复合语句,将被试作一条语句进行处理。如下:
#include <stdio.h>
int main()
{
int age = 0;
scanf("%d", &age);
if (age >= 18) //if 后使⽤{} 控制多条语句-这个块也叫:程序块,或者复合语句
{
printf("成年了\n");
printf("可以交⼥朋友了\n");
}
else //else 后使⽤{}控制多条语句-这个块也叫:程序块,或者复合语句
{
printf("未成年\n");
printf("不可以早恋哦\n");
}
return 0;
}
1.4 嵌套if
形式1
在 if else 语句中, else 可以与另⼀个 if 语句连用,构成多重判断。如下:
#include <stdio.h>
int main()
{
int num = 0;
scanf("%d", &num);
if (num > 0) //该if语句大括号内就是嵌套的另一个if
{
if (num % 2 == 0)
printf("偶数\n");
else
printf("奇数\n");
}
else
{
printf("输⼊的值是负数\n");
}
return 0;
}
代码逻辑是:在原先if else的基础上,若进入if语句,则再进行一个或多个if else 的条件判断。
实现:即在if的复合语句(大括号)内再写一个if else语句,若还想再嵌套,就在新加的if后加一个大括号,在里面继续写if else语句,可以一直嵌套下去。
形式2
#include <stdio.h>
int main()
{
int num = 0;
scanf("%d", &num);
if (num == 0)
printf("输⼊的数字是0\n");
else if (num > 0) //这⾥的if 相当于嵌套在else语句中,形成了嵌套结构
printf("输⼊的数字是正数\n");
else
printf("输⼊的数字是负数\n");
return 0;
}
实现:在if else语句的else语句处,置一个if语句,即当第一个if else语句执行的是else语句时,执行嵌套的if语句,只不过这个if语句写在了else语句处。
1.5 悬空else问题
如果有多个 if 和 else ,可以记住这样⼀条规则, else 总是跟最接近的 if 匹配。
分析如下代码:
#include <stdio.h>
int main()
{
int a = 0;
int b = 2;
if (a == 1)
if (b == 2) //else跟这个if匹配
printf("hehe\n");
else
printf("haha\n");
return 0;
}
我们可以看到,else和最接近自己的if匹配,我们要注意不要被对齐和不对齐所迷惑。当然这里我们最好要养成良好的代码书写习惯,将else与对应的if对齐,这样可以增加代码的可读性,不容易造成误解。
2. switch语句
2.1 定义
除了 if 语句外,C语⾔还提供了 switch 语句来实现分支结构。
switch 语句是一种特殊形式的 if…else 结构,用于判断条件有多个结果的情况。它把多重
的 else if 改成更易用、可读性更好的形式。
switch(表达式)
{
case 1: statement
case 2: statement
default: statement
}
我们要注意的点有:
- 当表达式的值与某case分支语句后的值匹配时则跳转到该条分支语句执行,都不匹配时跳转到 default语句执行
- case和后面的值之间必须有空格
- case后的值,必须是数字或整形常量表达式
2.2 switch示例,和与if的对比
示例:输入任意⼀个整数值,计算除3之后的余数
if实现:
#include <stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);
if (n % 3 == 0)
printf("整除,余数为0\n");
else if (n % 3 == 1)
printf("余数是1\n");
else
printf("余数是2\n");
return 0;
}
switch实现:
#include <stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);
switch (n % 3)
{
case 0:
printf("整除,余数为0\n");
break;
case 1:
printf("余数是1\n");
break;
case 2:
printf("余数是2\n");
break;
}
return 0;
}
2.2 switch语句中的break
示例:输入任意⼀个整数值,计算除3之后的余数
#include <stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);
switch (n % 3)
{
case 0:
printf("整除,余数为0\n");
case 1:
printf("余数是1\n");
case 2:
printf("余数是2\n");
}
return 0;
}
我们随便测试了一组发现打印的结果有两个,这是为什么呢?在switch语句中,只有遇到break才会跳出switch语句,如果某一个 case 语句的后边没有 break 语句,代码会继续向下执行,有可能执行其他 case语句中的代码,直到遇到 break 语句或者 switch 语句结束。就比如上面的代码就执行了 case 2 中的语句。
2.3 switch语句中的case与default顺序问题
在 switch 语句中 case 语句和 default 语句是没有顺序要求的,只要你的顺序是满足实
际需求的就可以。
不过我们通常是把 default 子句放在最后处理的。
二、关系操作符与逻辑操作符
在c语言的表达式中我们常需要进行比较和逻辑判断,因此下面我们来介绍一下常用的用于比较的关系运算符和用于逻辑判断的逻辑操作符
1.关系操作符
1.1 定义
C语言用于比较的表达式,称为 “关系表达式”(relational expression),里面使用的运算符就称为“关系运算符”(relational operator),主要有下面6个。
>
大于运算符<
小于运算符>=
大于等于运算符<=
小于等于运算符==
相等运算符!=
不想等运算符
我们注意一下相等和不相等运算符即可,其他的与数学中的思想及形式相一致。下面来看一下关系表达式的例子。
1.2 关系表达式
a == b;
a != b;
a < b;
a > b;
a <= b;
a >= b;
我们要注意关系表达式作为一个表达式不仅仅是用来表示关系的,通常我们需要利用这个关系,所以表达式会返回一个值作为表达式的计算结果给机器进行操作,关系表达式通常返回 0 或 1 ,表示真假比如,20 > 12
返回 1 , 12 > 20
返回 0。
1.3 多个关系操作符连用
i < j < k
这种书写形式通常不会达到我们想要的效果即表示 j 的值在 i 和 k 之间。因为关系运算符是从左到右计算,所以实际执行的是下方式子。
( i < j ) < k
上面式子中, i < j 返回 0 或 1 ,所以最终是 0 或 1 与变量 k 进行比较。如果想要判断变量 j的值是否在 i 和 k 之间,应该使用下面的写法。其中&&为逻辑操作符,后面我们马上就会进行讲解。
i < j && j < k
2.逻辑操作符
2.1 定义
逻辑运算符提供逻辑判断功能,用于构建更复杂的表达式,主要有下面三个运算符。
!
逻辑取反运算符(改变单个表达式的真假)&&
与运算符,就是并且的意思(两侧的表达式都为真,则为真,否则为假)||
或运算符,就是或者的意思(两侧至少有⼀个表达式为真,则为真,否则为假)。
2.2 短路
C语言逻辑运算符还有⼀个特点,它总是先对左侧的表达式求值,再对右边的表达式求值,这个顺序是保证的。如果左边的表达式满足逻辑运算符的条件,就不再对右边的表式求值。这种情况称为“短路”。如下方代码:
if(month >= 3 && month <= 5) //1.
if(month == 12 || month==1 || month == 2) //2.
1.
当&&左操作数(表达式最终结果也是个数)month>=3 结果为0时,根据&&操作符的定义知道,即使不判断右操作数,整个表达式结果也为0。
2.
同理,如果month == 12,则不用再判断month是否等于1或者2,整个表达式的结果也是1
像这种仅仅根据左操作数的结果就能知道整个表达式的结果,不再对右操作数进行计算的运算称为短路求值。
三、循环语句(循环结构)
1.while循环
1.1 定义
while(表达式)
循环体语句; //如果循环体想包含更多的语句,可以加上大括号
1.2 while循环的执行流程
1.3 while循环示例
示例:在屏幕上打印1~10的值
#include <stdio.h>
int main()
{
int i = 1;
while (i <= 10)
{
printf("%d ", i);
i = i + 1;
}
return 0;
}
2.for循环
2.1 定义
for(表达式1; 表达式2; 表达式3)
语句;//如果循环体想包含更多的语句,可以加上大括号
- 表达式1 用于循环变量的初始化
- 表达式2 用于循环结束条件的判断
- 表达式3 用于循环变量的调整
- 值得注意的是,这三个表达式均可省略不写,编译可以正常运行,但要注意表达式2也就是用于判断循环结束条件的,如果省略不写,那么代码将会无限循环下去,最终崩溃。
2.2 for循环的执行流程
2.3 for循环示例
示例:在屏幕上打印1~10的值
#include <stdio.h>
int main()
{
int i = 0;
for (i = 1; i <= 10; i++)
{
printf("%d ", i);
}
return 0;
}
2.4 for循环与while循环的对比
我们注意到for循环的初始化,判断,调整语句放在了一起,而while循环的三个语句位置是不一定的,当代码量增大的时候,如果我们想修改这三个语句,在while中查找是很麻烦的,而在for中很容易就找到了。因此使用for有利于代码的维护。
3. do-while循环
3.1 定义
do
循环体语句; //多条语句可使用大括号
while(表达式); //判断部分
- do-while 就是将while的循环体语句写在do后 ,按代码基本行逻辑我们也可以看出,先执行do后的循环体语句,再执行while判断部分。其中循环体语句不受while约束,即while执行0次时do也会执行。
3.2 do-while执行流程
3.3 do-while示例
示例:在屏幕上打印1~10的值
#include <stdio.h>
int main()
{
int i = 1;
do
{
printf("%d ", i);
i = i + 1;
} while (i <= 10);
return 0;
}
4. 循环嵌套
示例:找出100~200之间的素数,并打印在屏幕上。
注:素数又称质数,只能被1和本身整除的数字。
#include <stdio.h>
int main()
{
int i = 0;
//循环1 产⽣100~200的数字
for (i = 100; i <= 200; i++)
{
int j = 0;
int flag = 1;//设置一个标志,初始为1时表示是素数
//循环2 产⽣2~i-1之间的数字
for (j = 2; j < i; j++)
{
if (i % j == 0) //判断i是否为素数,即余数为0,能整除就不是素数
{
flag = 0; //改变flag值为0,标志为假
break;
}
}
if (flag == 1) //循环2结束后如果flag未被改变,即2~i-1的数都不能整除
printf("%d ", i); //说明为素数,打印
}
return 0;
}
5. goto语句
5.1 定义
C语言提供了一种非常特别的语法,就是 goto 语句和 跳转标号。goto 语句可以实现在同⼀个函数内跳转到任意设置好的标号处。
- goto语句只能在当前函数中使用,无法跳转到其他函数
- goto使用过多会给阅读代码造成麻烦,即使是代码的编写者在一段时间后也容易弄混跳转的位置,可读性差,即使没有goto语句,我们也能正常编写出所需的代码,因此goto语句非必要情况不要使用,不建议使用
5.2 示例:快速脱离多层循环
上面我们说goto语句不建议使用是针对大部分情况,但俗话说存在即合理。下面我们就来介绍一种使用goto的情景。
for (...)
{
for (...)
{
for (...)
{
if (disaster)
goto next;
}
}
}
next:
//...
我们可以看到在多层嵌套循环中,如果使用break只能跳出所在的一层循环,要想全部跳出必须每一层循环都加上break,十分麻烦,而使用goto语句则可以直接跳出,到达next标志处。
此处也可见goto语句的强大,不管三七二十一,只要在一个函数内,想跳哪就跳哪,但也正是这种随意性我们必须谨慎使用它,以免出现意外情况。下面是一些注意点:
- next为自定义名字的跳转符号
- next:独占一行,后接其他代码。(注意不要漏掉冒号)
四、break与continue关键字
在循环执行的过程中,如果某些状况发生的时候,需要提前终止循环,这是非常常见的现象。C语言中
提供了 break 和 continue 两个关键字,用于终止循环。
1.定义
-
break 的作用是用于永久的终止循环,只要 break 被执行,直接就会跳出循环,继续往后执行。但break本身的作用是跳出当前的语句(复合语句),当处于嵌套循环时,我们可能需要多次使用break。我们在switch中也使用过这个关键字。
-
continue的作用是跳过循环体中continue后的代码,返回循环语句的判断表达式处进行下一次判断,如果循环的调整部分位于continue后,那么代码可能会进入死循环。
2.示例
2.1 break示例
#include <stdio.h>
int main()
{
int i = 1;
while (i <= 10)
{
if (i == 5)
break;//当i等于5后,就执⾏break,循环就终⽌了
printf("%d ", i);
i = i + 1;
}
return 0;
}
2.2 continue示例
#include <stdio.h>
int main()
{
int i = 1;
while (i <= 10)
{
if (i == 5)
continue;
//当i等于5后,就执⾏continue,直接跳过continue的代码,去循环的判断的地⽅
//因为这⾥跳过了i = i+1,所以i⼀直为5,程序陷⼊和死循环
printf("%d ", i);
i = i + 1;
}
return 0;
}
总结
本文主要介绍了C语言中的分支结构丶循环结构对应的几种语句,常用的关系操作符和逻辑操作符,文章中有什么不对的丶可改正的丶可优化的地方,欢迎各位来评论区指点,博主看到后会一一回复