本篇前言:C语言是结构化的程序设计语言!而所有的结构又可大致分为三种,分别是:顺序结构,选择结构,循环结构。 顺序就是从前往后,从上到下,我们的写好的程序就是按顺序从第一行起被一行一行的编译的 选择也叫分支,是同一时间点面对问题时,有不同的选择,我们选其一而行 循环是指程序进入了一段不断重复的路,可能会一直在此循环往复,也可以打破循环,继续前进。 在顺序执行的程序中,分支中可能有循环,循环中也可能有分支。分支和循环是让我们的代码变得多姿多彩的关键技能! 画图解释如下: 
下面,重点来细说选择结构和循环结构。 在C语言中,分支语句有if语句和switch语句;循环语句有while语句,for语句,do while 语句;还有不同于分支和循环的goto语句。
分支语句
1.if-else 语句 if-else语句就是由if、else(、else if)组成的语句块。它是分支语句的一种,也是我们写出选择结构必须掌握的语句。我在这里不厌其烦的把if-else语句分成了三种:单if语句、if-else双分支语句、if - else if - else多分支语句。 1)单if语句:即只有if的分支语句 语法
if(条件表达式) { 执行的语句; }
代码案例
#include<stdio.h>
int main()
{
int age = 20;
if (age > 18)
printf("可以考驾照\n");
return 0;
}
运行结果:  代码分析:由于age=20,20>18,if后()里的条件判断为真,所以执行语句printf(“可以考驾照\n”); 注:能否进入if语句得看if后的()中的值为真还是为假,为真则执行该语句,为假不执行。
知识总结: 1.C语言中if后的条件判断:非零为真,零为假 2.不加大括号时if仅与其后最近的一条语句配对(较易理解,不多说啦)
2)if-else 双分支语句 双分支语句其实就是判断题,非if即else 给出语法:
if(条件表达式) { 执行的语句1; } else { 执行的语句2; }
条件表达式为真,执行if后语句,条件表达式为假,执行else后语句 代码案例:
#include<stdio.h>
int main()
{
int age = 0;
scanf("%d",&age);
if (age >= 18)
printf("adult\n");
else
printf("nonage\n");
}
运行结果   3)if - else if - else多分支语句 多分支语句就是将判断题变成了多选题 给出语法:
if(条件表达式1) { 执行的语句1; } else if(条件表达式2) { 执行的语句2; } … else if(条件表达式n) { 执行的语句n; } else { 执行的语句n+1; }
条件表达式1为真则执行语句1,条件表达式2为真则执行语句2,以此类推,条件表达式n为真,执行语句n; 如果,以上的n个条件都不满足,执行else下的语句n+1。 代码案例
int main()
{
int score = 80;
if (score >= 0 && score < 60)
printf("挂科\n");
else if (score >= 60 && score < 70)
printf("中等\n");
else if (score >= 70 && score <= 90)
printf("良好\n");
else if (score >= 90 && score <= 100)
printf("优秀\n");
else
printf("成绩出错\n");
}
运行结果  
注:在写if/esle if后面()中的判断语句时,初学者容易常出的错误 例1:(判断语句书写不规范问题) 将
if (score >= 0 && score < 60)
容易写成
if (0 <= score < 60)
如果我们这么写,我们来测试一下程序的结果是什么(假设成绩是80) 很明显发生了错误,但是为什么呢,老师看你不爽? 原因: if (0 <= score < 60) 的逻辑是:先执行“0 <= score”,score为80,所以表达式“0 <= score”为真,表达式的结果就是1,然后“1 < 60”这个表达式也是真,所以if后()内的表达式值为1,直接打印了“挂科”。切记以后不要写出这样的错误语法。
例2 将
if (20 == a)
写成
if (20 = a)
这样程序就会直接报错 
例3:(悬空else的匹配问题) 看这段代码
int main()
{
int a = 10;
int b = 20;
if (a == 20)
if (b == 20)
printf("%d", b);
else
printf("%d", a);
return 0;
}
结果是什么都不打印,是不是与你想象中的不一样,原因是else默认与离自己最近的未匹配的if匹配。上面的程序书写风格不好,在我们的编程软件(Visual Studio 2019)上这段代码实际上会被自动的排版成下面这种形式
int main()
{
int a = 10;
int b = 20;
if (a == 20)
if (b == 20)
printf("%d", b);
else
printf("%d", a);
return 0;
}
所以代码风格很重要。 建议:适当的使用{ }可以使代码逻辑更清楚。
2.switch语句 switch语句是一种适用于处理多分支的语句 给出语法:
switch (整形表达式) { case 整形常量表达式1: 语句1; case 整形常量表达式2: 语句2; }
switch后面的()内是整形表达式,就是说这个表达式结果的数据类型必须是整形,case后面的表达式是整形常量表达式,就是说这个表达式不仅结果必须是整形,而且结果必须是常量。 这个语法我们这样理解:switch的英文意思是开关,那么switch后面整形表达式的值代表的就是这个开关在哪里被打开,也就是说这个整形表达式的值决定了整个switch程序块的入口 例如下代码
int main()
{
int day = 3;
switch (day)
{
case 1:
printf("工作\n");
case 2:
printf("工作\n");
case 3:
printf("工作\n");
case 4:
printf("工作\n");
case 5:
printf("工作\n");
case 6:
printf("休息\n");
case 7:
printf("休息\n");
}
return 0;
}
结果为  从上面的程序中就可以看出,程序是从上往下的,从这个入口(day = 3,也就是case 3)开始,一行一行的执行。但是光是这样,switch是做不到分支的功能的,所以我们还需要一个出口,这里就要用到break。 break关键字 break充当的是switch程序块出口的角色。break是一个关键字,作用是让程序读到它时跳出自己当前所在的子程序。这样,程序块就被分划成了不同的部分,我们才能实现分支的功能,效果如下
int main()
{
int day = 6;
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;
}
return 0;
}
 程序从case 6入口进入,然后读了一句printf(“休息\n”),再读到break出口出选择程序块 小建议:swtich语句块的最后一项不管加不加break都可以跳出程序,但是编程的好习惯是加上,这样便于以后别人或我们修改程序增添case。 default子句 default子句和if-else中的else作用类似,都是将前面所有情况的补集作为自己的触发条件,也就是说前面的所有情况的条件判断都为假就执行它,而且它和else一样,并不是必须得存在。由于是所有情况的补集,所以default和else都至多只能出现一次。
小结: switch的入口是case ,出口是break。 break;直接跳出switch语句,不执行后续操作 default:当case中所有的整型变量表达式均不满足时,执行default中的语句,default可以写在任意case语句可以出现的位置,没有顺序可言,没有强规定将default只能放到前面或后面。(不过一般习惯将default放到后面)
3.分支语句的嵌套 分支语句也就是if语句和switch语句,都是可以嵌套的。所谓分支嵌套就是在分支中再加入分支,这样我们就可以描述相对比较复杂的情况。 if-else语句嵌套
int main()
{
int a = 1;
int b = 0;
if (a == 1)
{
printf("上大学\n");
printf("你是否要努力学习?(1/0):");
scanf("%d", &b);
if (b == 1)
print("找到好工作\n");
else
printf("放飞自我,毕业即失业\n");
}
return 0;
}
 switch嵌套
#include <stdio.h>
int main() {
int x = 3;
int y = 3;
switch (x % 2) {
case 1:
switch (y)
{
case 0:
printf("first");
case 1:
printf("second");
break;
default: printf("hello");
}
case 2:
printf("third");
}
return 0;
}
结果为 
循环语句
循环语句就是一些语句重复执行多次。C语言中的循环结构有三种常见的语句,分别是while、for、do-while循环,他们大同小异,结构上基本都分为初始化部分、条件判断部分、调整部分,下面一起来学习一下。
1)while循环语句 语法:
while(表达式) { 循环语句; } 其他语句
解释:当表达式的值为真(非零)时;就重复执行循环语句,直到表达式的值为假(零),则跳出循环,执行其他语句。 例如我们实现:在屏幕上打印1-10的数字。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int i = 1;
while (i <= 10)
{
printf("%d ", i);
i++;
}
return 0;
}
结果为:  while语句中的break和continue 接下来看一下while循环的执行流程图:  break在while循环中的作用:由图我们可以看出,当当循环中遇到break时,就会停止后期的所有循环,直接终止循环。 例:
int main()
{
int i = 1;
while (i <= 10)
{
if (i == 5)
break;
printf("%d ", i);
i = i + 1;
}
return 0;
}
结果:  所以,while中的break是用于永久终止循环的。
continue在while循环中的作用:continue是用于终止本次循环的,也就是本次循环中的continue后边的代码不会再执行,而是直接跳转到while语句的判断部分,进行下一次循环的入口判断。 例:
int main()
{
int i = 1;
while (i <= 10)
{
if (i == 5)
continue;
printf("%d ", i);
i = i + 1;
}
return 0;
}
结果:  解释:即当i=5的时候,后面的语句直接跳过,再回到判断语句中继续执行,此时 i 还是为5,继续跳过,这样下去就一直死循环下去。
2)for循环语句 语法:
for(表达式1,;表达式2;表达式3) 循环语句;
其中表达式1为初始化部分,用于初始化循环变量;表达式2为条件判断部分,用于判断循环时候终止;表达式3为调整部分,用于循环条件的调整。 例:使用for循环在屏幕上打印1-10的数字
int main()
{
int i = 0;
for (i = 1; i <= 10; i++)
{
printf("%d ", i);
}
return 0;
}
结果:  for语句中的break和continue 接下来看for循环的流程执行图:  我们发现在for循环中也可以出现break和continue,它们的意义和在while循环中的是一样的。但还是存在些差异;具体例子如下:   从上面代码及结果可见,在for循环中,当程序遇到break时,直接跳出循环,终止循环;当遇到continue时,跳过后面的语句,到达调整部分,执行调整语句后再到判断部分继续执行程序。
此外,关于for语句还有一些建议: 1、不可以在for循环体内修改循环变量,防止for循环失去控制。 2、建议for语句的循环控制变量的取值采用“前闭后开区间”写法。 关于变量的写法: (提倡第一种写法,容易理解且判断部分的数字有特殊意义,即代表循环的次数)
int i0;
for(i=0;i<10;i++)
{}
for(i=0;i<=9;i++)
{}
下面在看一下一些for循环的变种 变种1:  出现这种死循环结果的原因是:当始化部分和调整部分省略时,程序不进行初始化,和后续的调整;而当判断部分省略时,则程序认为判断部分恒为真,所以程序会一直运行下去。
变种2:  以上我们可以看出,for循环的控制变量是允许有2个变量存在的,但当有2个变量存在时,需格外谨慎才不会出错。
3)do-while()循环语句 语法:
do 循环语句; while(表达式);
循环执行流程图如下: 
程序逻辑:先执行一次循环语句,在进行条件判断是否继续循环。与for和while循环的区别在于do-while语句至少可以循环一次。 案例如下:
int main()
{
int i = 1;
do
{
printf("%d ", i);
i++;
} while (i <= 10);
return 0;
}
 do-while循环使用场景有限,总体使用频率看:for循环>while循环>do-while循环。所以理解前两种循环后,do-while循环就会很容易理解,这里就不做多的详解啦。 关于do-while循环中continue和break的应用和前面while、for循环中的应用原理一样,这里就不多赘述。(查上述流程执行图就可理解看懂)
goto语句
goto语句的使用方法: goto语句相当于一个传送门,可以直接改变代码执行的逻辑,即可以直接跳到目标代码去执行。但它如一把双刃剑,用得好编程效果很不错,滥用就会自废武功。 语法如下:
goto 标记名称;
标记名称:其他语句;
举例运用一下goto语句
int main()
{
int age = 0;
again:
scanf("%d", &age);
if (age < 18 && age >= 1)
printf("未成年\n");
else if (age >= 18 && age <= 121)
printf("成年\n");
else
{
printf("输入错误,请重新输入\n");
goto again;
}
return 0;
}
 我们输入180的时候,执行else里的语句,先执行printf(“输入错误,请重新输入\n”)然后执行goto again,again在程序最开始,所以我们可以重新输入然后继续进行选择判断。
从理论上goto语句是没必要的,在实践中没有goto语句也可以很容易的写出代码。但是在某些场合下goto语句还是用得着的,最常见的用法就是终止程序在某些深度嵌套的结构的处理过程,例如一次跳出两层或多层循环。这种情况下用break是达不到目的的,因为break只能跳出一层循环,即只能从最内层循环退出到上一层循环。 goto语句真正适合的场景案例如下:
for(...)
{
for(...)
{
for(...)
{
if(disaster)
goto error;
}
}
}
...
error:
if(disaster)
...
可见在类似于上述的程序中,运用一个goto语句,就能直接跳出多层循环,此种方法就比较简洁。但需格外注意,goto语句只能在一个函数范围内跳转,不能跨函数。
自此,第一篇讲解结束,如有不详细或者不周到的地方,望大家指正!
|