> 文章列表 > 【C语言】分支语句和循环语句(上)

【C语言】分支语句和循环语句(上)

【C语言】分支语句和循环语句(上)

【C语言】分支语句和循环语句(上)

  • 前言
  • 1.分支语句和循环语句
  • 2.什么是语句
  • 3.分支语句(选择语句)
    • 3.1 if语句
      • 3.1.1 悬置else
      • 3.1.2 if的书写形式对比
      • 3.1.3 在线练习
    • 3.2 switch语句
      • 3.2.1 switch语句中的break的作用
      • 3.2.2 default子句
      • 3.2.3在线练习
  • 4.循环语句
    • 4.1 while
      • 4.1.1 while语句中的break和continue

所属专栏:C语言
博主首页:初阳785
代码托管:chuyang785
感谢大家的支持,您的点赞和关注是对我最大的支持!!!
博主也会更加的努力,创作出更优质的博文!!
关注我,关注我,关注我,重要的事情说三遍!!!!!!!!

前言

我们说C语言是结构体的程序设计语言。
C语言中有三种结构:

  1. 顺序结构
  2. 选择结构
  3. 循环结构

而今天我们要讲的就是选择语句和循环语句。

1.分支语句和循环语句

我们的分支语句和循环语句有以下内容:
分支语句

  • if
  • switch

循环语句

  • while
  • for
  • do while
  • goto语句

2.什么是语句

C语句可分为以下五类:

  1. 表达式语句
  2. 函数调用语句
  3. 控制语句
  4. 复合语句
  5. 空语句
    本章后面介绍的是控制语句
    控制语句用于控制程序的执行流程,以实现程序的各种结构方式(C语言支持三种结构:顺序结构、选择结构、循环结构),它们由特定的语句定义符组成,C语言有九种控制语句。
    可分成以下三类:
  6. 条件判断语句也叫分支语句:if语句、switch语句;
  7. 循环执行语句:do while语句、while语句、for语句;
  8. 转向语句:break语句、goto语句、continue语句、return语句。

3.分支语句(选择语句)

所谓分支就是有多个支点,就像我们的分叉入口一样,这个时候我们就要进行选择,于是我们就有了分支语句,用于选择。

3.1 if语句

1. 单分支语句

语法结构:
if(表达式)语句;

我们可以举个例子

#include <stdio.h>
int main()
{int age = 0;scanf("%d", &age);if(age<18){printf("未成年\\n");}
}

2. 双分支语句

if(表达式)语句1;
else语句2;

例如:

#include <stdio.h>
int main()
{int age = 0;scanf("%d", &age);if(age<18){printf("未成年\\n");}else{printf("成年\\n");}
}

3. 多分支语句

if(表达式1)语句1;
else if(表达式2)语句2;
else语句3;

例如:

#include <stdio.h>
int main()
{int age = 0;scanf("%d", &age);if(age<18){printf("少年\\n");}else if(age>=18 && age<30){printf("青年\\n");}else if(age>=30 && age<50){printf("中年\\n");}else if(age>=50 && age<80){printf("老年\\n");}else{printf("老寿星\\n");}}

上面我们要注意的一点就是我们在判断30<=age<=50的时候不能直接把这个表达式写上去,一位我们的编译器会先判断 30<=age(假如我们的age是15) 30<=15为假就是0,在会判断0<=50为真就会打印内容,所以我们这里要用到我们之前讲过的逻辑操作符&&(与)。

上面的多分支表达式有的同学就可能有这样的疑问,就是将上面的else if都改成if不是也可以吗

#include <stdio.h>
int main()
{int age = 0;scanf("%d", &age);if(age<18){printf("少年\\n");}if(age>=18 && age<30){printf("青年\\n");}if(age>=30 && age<50){printf("中年\\n");}if(age>=50 && age<80){printf("老年\\n");}if(age>80){printf("老寿星\\n");}
}

从理论上讲这个样的方式是可以的,但是有一定的缺陷。
如果我们全是if语句的话,我们在进行判断的时候编译器会将所有的if语句都判断一边,也就是说如果我们有N个判断语句,那无论我们想判断那个表达式编译器都会判断N遍后输出值。

但是如果我们用else if的话就不一样了,只要进入了else if语句后判断成功就直接退出判断,也就是说用else if语句最多要判断N次。

注意:我们在写if或者else或者else if的时候我们要加上{ }
比如:

 int main(){int age=0;scanf("%d",&age);if(age>7)printf("可以上小学了");printf("可以交到好朋友");return 0;}

我们看上面一串代码,无论我们输入的age大于7还是小于7都会大于“可以交到好朋友”。
这是因为我们的 if 或者 else 或者 else if 后面默认是控制一条语句的(语句你可以认为是一个;代表一条语句),所以如果我们想控制多条语句的话就必须加上{ }。

 int main(){int age=0;scanf("%d",&age);if(age>7){printf("可以上小学了");printf("可以交到好朋友");}return 0;}

所以这里给的一个建议就是:
无论我们用判断语句进行判断的时候都尽量加上{ }养成好的编程习惯。

3.1.1 悬置else

我们用一串代码来讲解悬置else

#include <stdio.h>
int main()
{int a = 0;int b = 2;if(a == 1)if(b == 2)printf("hehe\\n");elseprintf("haha\\n");return 0;
}

上面打印的是什么呢?
相信大多数人的第一眼肯定认为是打印haha,但是事实上却不是。
答案是什么都没有打印。

这就要讲到else的匹配原则了:else是和它最近的if匹配的。

所以这里我们的else是和if(b2)匹配的。
判断顺序:if(a
1)判断为假,没有进行判断if(b==2)就直接跳出去了,所以什么都没有执行。
我们来修改一下,让它更明显一点:

#include <stdio.h>
int main()
{int a = 0;int b = 2;if(a == 1){if(b == 2){printf("hehe\\n");}else{printf("haha\\n");}}return 0;
}

样就更能清楚的知道为什么没有输出任何值了。

所以这里就要再次强调一下我们在编写代码的时候要养成良好的代码风格。
适当缩进,加上{ }等。
在未来的笔试面试的时候写出清晰的代码,可以给面试官一个良好的第一印象,为自己找到一个好工作做好准备。

这里推荐一本书:《高质量C/C++编程》

3.1.2 if的书写形式对比

//1:
if(function)
{return x;
}
return y;
//2:
if(function)
{return x;
}
else
{return y;
}

上面的两个样式的结果是一样的。
这里我们就要明白return的含义,一般我们写一个函数的时候,如果需要返回一个值的话就要用到return一旦我们return了函数也就结束了,也就说不会在执行以后的代码块了,所以第一种写法进入if语句一点return x后就直接退出程序了,没有机会执行return y这个功能了,这个就和
if else的功能一样了。

这里我们还要强调的一点就是一个=和两个==的区别

int main()
{int n=10;if(n=10)printf("%d",n);return 0;
}

这里我们看到我们if(n=10)只写了一个=,而我们知道一个等号的意思是赋值的意思,所以我们if语句里面的表达式的就是10,如果我们写一个n=5,它还是会执行printf函数。
所以我们一定要区别一个=和两个==的不同意义。

3.1.3 在线练习

练习1:判断一个书是否为奇数
答案:

int main()
{int n = 0;scanf("%d", &n);if (n % 2 == 0){printf("不是奇数\\n");}else{printf("是奇数\\n");}return 0;
}

练习2:判断1-100之间的奇数
答案:

int main()
{int i = 1;while (i <= 100){if (i % 2 == 1){printf("%d", i);i++;}}return 0;
}

3.2 switch语句

switch语句也是一种分支语句。
常常用于多分支的情况。
比如:

输入1,输出星期一
输入2,输出星期二
输入3,输出星期三
输入4,输出星期四
输入5,输出星期五
输入6,输出星期六
输入7,输出星期日

那我没写成 if…else if …else if 的形式太复杂,那我们就得有不一样的语法形式。

于是我们就有了switch……case语句:

switch(整型表达式)
{case (有个空格)整形常量:(注意是:不是;)case+空格+整形常量+:
}

如果我们写成:

int n=9;
swhich(n)
{case n:
}

这个时候就出错了,n是变量不是常量。
我们就可以实现以下功能:

#include <stdio.h>
int main()
{int day = 0;scanf("%d", &day);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;
}

3.2.1 switch语句中的break的作用

在上面我们实现一下输出星期的功能:
在这里插入图片描述
会发现他并没输出我们想要的星期一,而是都输出了一遍。
这是因为我们的switch……case语句是一次执行的,也就是说我们的case相当于入口,这个时候我们就要有一个出口,break就是我们的出口:

#include <stdio.h>
int main()
{int day = 0;switch(day){case 1printf("星期一\\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;
}

有时候我们的需求变了:

  1. 输入1-5,输出的是“weekday”;
  2. 输入6-7,输出“weekend”

所以我们的代码就应该这样实现了:

#include <stdio.h>
//switch代码演示
int main()
{int day = 0;scanf("%d",day);switch(day){case 1case 2:case 3:case 4:case 5:printf("weekday\\n");break;case 6:case 7:printf("weekend\\n");break;}return 0;
}

break语句 的实际效果是把语句列表划分为不同的分支部分。

编程好习惯
在最后一个 case 语句的后面加上一条 break语句。
(之所以这么写是可以避免出现在以前的最后一个 case 语句后面忘了添加 break语句)。

3.2.2 default子句

如果表达的值与所有的case标签的值都不匹配怎么办?

其实也没什么,结构就是所有的语句都被跳过而已。
程序并不会终止,也不会报错,因为这种情况在C中并不认为是个错误。
但是,如果你并不想忽略不匹配所有标签的表达式的值时该怎么办呢?
你可以在语句列表中增加一条default子句,把下面的标签
default:
写在任何一个 case 标签可以出现的位置。
当 switch 表达式的值并不匹配所有 case 标签的值时,这个 default 子句后面的语句就会执行。
所以,每个switch语句中只能出现一条default子句。
但是它可以出现在语句列表的任何位置,而且语句流会像执行一个case标签一样执行default子句。
编程好习惯
在每个 switch 语句中都放一条default子句是个好习惯,甚至可以在后边再加一个 break 。

#include <stdio.h>
int main()
{int day = 0;scanf("%d",day);switch(day){case 1case 2:case 3:case 4:case 5:printf("weekday\\n");break;case 6:case 7:printf("weekend\\n");break;default:printf("输入错误");}return 0;
}

如果我们输入的day不是1-7之间的数他就会输出”输入错误“。

3.2.3在线练习

#include <stdio.h>
int main()
{int n = 1;int m = 2;switch (n){case 1:m++;case 2:n++;case 3:switch (n){//switch允许嵌套使用case 1:n++;case 2:m++;n++;break;}case 4:m++;break;default:break;}printf("m = %d, n = %d\\n", m, n);return 0;
}

上面的m和n个是多呢?
答案:
m=5,n=3;

4.循环语句

  • while
  • for
  • do while

4.1 while

我们已经掌握了,if语句:

if(条件)语句;

当条件满足的情况下,if语句后的语句执行,否则不执行。
但是这个语句只会执行一次。
由于我们发现生活中很多的实际的例子是:同一件事情我们需要完成很多次。
那我们怎么做呢?
C语言中给我们引入了: while 语句,可以实现循环。

//while 语法结构
while(表达式)循环语句;

比如:打印1-20的数:

#include <stdio.h>
int main()
{int i = 1;while(i<=20){printf("%d ", i);i = i+1;}return 0;
}

4.1.1 while语句中的break和continue

break介绍:

#include <stdio.h>
int main()
{int i = 1;while(i<=20){if(i==10){break;}printf("%d ", i);i = i+1;}return 0;
}

展示:
在这里插入图片描述
我们看到代码并没有执行打印1-20的结果,而是打印到9就停止了。
这是因为我们的break有终止循环的作用。
当i==10之后进入break,break终止循环,循环结束所以只打印1-9.

总结:

break在while循环中的作用:
其实在循环中只要遇到break,就停止后期的所有的循环,直接终止循环。
所以:while中的break是用于永久终止循环的。

continue介绍:
如果我们讲上面的break换成continue会发生什么:

#include <stdio.h>
int main()
{int i = 1;while(i<=20){i = i+1;if(i==10){break;}printf("%d ", i);}return 0;
}

在这里插入图片描述
我们看到上面的打印结果没有10。

continue在while循环中的作用就是:

continue是用于终止本次循环的,也就是本次循环中continue后边的代码不会再执行,
而是直接跳转到while语句的判断部分。进行下一次循环的入口判断。

我们再看一串代码:
再看之前我们先了解以下getchar()。
getchar()是字符输入函数

int gethcar(void);

在这里插入图片描述
getchar()读取成功返回这个字符的ASCII码,读取失败返回EOF(本质上EOF是-1)
与之配套的是putchar(),打印一个字符。

//代码什么意思?
//代码1
#include <stdio.h>
int main()
{int ch = 0;while ((ch = getchar()) != EOF)putchar(ch);return 0;
}

这里如果我们想要结束程序的时候只需要按CTRL+z就能结束了,但是有些编译器可能要按不止一次CTRL+z才能结束。

这里的代码适当的修改是可以用来清理缓冲区的.
//代码2
#include <stdio.h>
int main()
{char ch = '\\0';while ((ch = getchar()) != EOF){if (ch < '0'|| ch > '9')continue;putchar(ch);}return 0;
}
//这个代码的作用是:只打印数字字符,跳过其他字符的、

注意:
在这里插入图片描述
我们这里会发现我们输入密码的时候他并没有出现让我们输入Y/N的时候,而是直接输出了确认失败的字样,这是怎么回事呢?

原因是我们的我们在输入密码123456的时候我们还敲了一个回车键,而回车键其实也是一个字符,而scanf是以回车键作为结束的标志,他没有拿到回车键。

这里再补充一个点就是我们的输入缓冲区,我们输入的字符都在缓冲区,而我们的scanf拿数据的时候是在输入缓冲区里面拿数据,你可以理解为输入缓冲区是一个储物柜,而我们输入123456+回车键放进输入缓冲区我们的scanf只拿到了123456,回车键没有被拿走被留在了输入缓冲区,而到了我们的第二个scanf的时候他也去输入缓冲区拿数据,他发现输入缓冲区有数据(回车键\\n)于是他就拿走了,这个时候就判断 \\n==‘Y’ 判断失败走了else(确认失败)。

改进:
在连个scanf直接加上一个getchar()。
我们用getchar()主动去把\\n拿走,让输入缓冲区没有数据了,这个时候,第二给scanf就可以进行输入数据了。

在这里插入图片描述
但是问题又来了:
在这里插入图片描述
当我们输入123456空格qwe的时候有出现了刚才的情况。
这是因为我们scanf读取到空格的时候也是认为认为结束读取的标志的,所我们的输入缓冲区就还剩空格qwe/n这几个字符,但是我们的getchar()又只能读取一个字符,所以我们这里就要用while循环:

#include <stdio.h>
int main()
{char password[20] = { 0 };printf("请输入密码:>");scanf("%s", password);printf("请确认密码(Y/N)");while ((getchar()) != '\\n'){;}char input = 0;scanf("%c", &input);if ('Y' == input)printf("确认成功\\n");elseprintf("确认失败\\n");return 0;
}

在这里插入图片描述