C语言——分支和循环语句(保姆级详解)

  • C语言是一种结构化的程序设计语言
    • 如下图所示,有三种结构,而世上几乎所有事情都可以用这三种结构表达:结构.png
    • 其中,顺序结构不必多说,就是自上而下的运行程序
    • 选择结构就是C语言中的分支语句,包含if语句switch语句
    • 循环结构则就是C语言中的循环语句,包含whilefordo while这三种语句
  • 那么,相信初入C语言大门的你一定很迷茫,什么是语句?语句有什么用呢?接下来我来简单的给你解释一下:

1、语句

语句可以理解为是编写代码所需的最小基本单位,无论是多大的项目都得由一行一行的语句堆砌起来,像是建房子用的砖头一样,虽然并不罕见但却必不可少。
而语句主要分为以下五类:

  1. 表达式语句
    1. eg:1+1;像这种是一个简单的表达式的语句,就是表达式语句
  2. 函数调用语句
    1. eg:printf("%d\n",a);像这种调用printf函数的语句,就是函数调用语句
  3. 控制语句
    1. 负责控制整个程序的运行,依靠语句实现各种上文提到的结构,此种语句为本文重点,将在下文展开讲解
  4. 复合语句
    1. 如果是一个大括号括起来,而里面有很多语句,这一整个大括号就是符合语句,里面实现了很多功能,但只是一个语句。
  5. 空语句
    1. 什么内容也没有,只有一个分号“;”

C语言中,共有9种控制语句:

  • 分支语句(实现选择结构):if;switch
  • 循环执行语句(实现循环结构):do while;while;for;
  • 转向语句(不具体实现某个结构,但起到了操控程序的作用):break;goto;continue;return

2、分支语句(选择结构)

选择、.png

2.1 if 语句

if的语法结构:

if(exp)
	语句;

exp是表达式的意思

那么我们就可以写一个代码来对上图的流程图进行一个实现:

#include <stdio.h>
int main()
{
	int a = 0;
	scanf("%d", &a);
	if (a == 1)
		printf("考进清北\n");
	else if ( a==0 )
		printf("进入大专\n");
	return 0;
}

在这个代码中,输入0表示不务正业,输入1表示好好学习
不难发现,else if表示其他的选择,也可以直接用else直接表示其他所有的选择情况

  • 代码运行结果如下:
    image.pngimage.png
  • if和else后默认只能跟一条语句,如果想执行多条语句的话需要用大括号括起来变成复合语句,也叫做代码块。
  • 在C语言中,0表示假,非0表示真(注意不是1表示真,是非0的任何数),所以if后的判断就是判断是否为0,如果是0就不执行,如果非0就执行

2.1.1悬空else

上文已经提到else语句,接下来我们更深入的学习一下else的坑:
思考:下面这段代码的结果是什么?

#include <stdio.h>
int main()
{
	int a = 0;
	int b = 2;
	if (a == 5)
		if (b == 2)
			printf("选择1");
	else
		printf("选择2");
	return 0;
}

聪明的你觉得是什么结果呢?选择1?还是选择2?

答案:都不是,什么都不打印。
运行图:image.png
为什么会出现这种情况呢?因为else语句是“就近原则”,和最近的一个if进行匹配。显然,这个代码的else和第二个if进行了匹配,而不是第一个ifimage.png
所以这种“悬空”的else,并不是和谁对齐,就和谁匹配。这也提醒我们,平常的代码风格需要注意缩进和空格,让代码阅读者不要产生歧义和误会,就是最好的。

2.1.2 if 语句书写形式的对比

思考:下面两种代码风格,哪个更好?

//代码1
if (condition) {
	return x;
}
return y;
//代码2
if (condition)
{
	return x;
}
else
{
return y;
}

虽然两段代码的功能是一样的,但很明显,第二段代码更加清晰易懂。

思考:下面两种风格哪个更好?

//代码3
int num = 1;
if(num == 5)
{
printf("lulu\n");
}
//代码4
int num = 1;
if(5 == num)
{
printf("lulu\n");
}

这个一眼可能看不出孰优孰劣,但其中最明显的区别在于if后的条件,一个是num == 5 ,一个是5 == num,那么这两个究竟哪个好呢?
举个例子,你就明白了:

#include <stdio.h>
int main()
{
	int a = 0;
	if (a = 5)
		printf("5\n");
	return 0;
}

快,想一下这个代码的结果是什么?是5还是不打印?

  • 答案是:image.png
    为什么会这样?因为条件那里不小心,少写了一个=号,从判断相等的条件变成了赋值,那么if后的条件自然变成了5,而5又是一个非0的数,非0即为真,所以if里的程序运行了。

那么如何避免这种不小心呢?我们可以从代码习惯入手:
把之前的a=5调换位置变成5=a,可以看到:
image.png
报错了
也就是说,如果你把数字和变量调换顺序的话,如果你少打了=号,程序根本运行不起来,从根本上解决了未来可能的bug的出现(因为这样很好发现问题)

那么我们再看代码4:

//代码4
int num = 1;
if(5 == num)
{
printf("lulu\n");
}

显然,是数字在前,变量在后的模式,与代码3虽然功能一样,但却减少了出错的概率以及调试的时间成本,不可谓不好。

2.1.3小练习

判断一个数是否为奇数(难度:⭐)

建议你先去编译器自己动手做一下,再继续看本文的教程


解析分割线

第一题思路:将输入的数字取模2,若余数为0则为偶数,余数为1为奇数
用if语句进行编写:

#include <stdio.h>
int main()
{
	int a = 0;
	scanf("%d", &a);
	if (a % 2)
		printf("是奇数");
	else
		printf("不是奇数");
	return 0;
}

这里因为余数是0即为假,非0即为真,所以直接写到if的条件里即可,你也可以用它的结果和0去比较是否相等,都可以。

2.2 switch 语句

switch语句是一种多分支的语句,与if……else if……else if功能上是一样的,但是他更为简洁,也更方便阅读。
switch的语法结构:

switch(整型表达式)
{
	语句项:
}

又出现了新名词:语句项,这是个什么鬼?
语句项就是case语句,语法结构如下:

case 整型常量表达式:
	语句;

可以发现,case和switch是嵌套着使用的
除此之外,还有一个叫做break的语句,搭配着就可以实现分支
case表示程序入口,break表示程序的出口。

2.2.1举个🌰:

比如我们输入一个数字,1是进清北,2是进c9,3是进985,4是进211,5是进双一流,6是进一本,7是进二本,8是进大专。
那么用switch语句是这样的:

#include <stdio.h>

int main()
{
	int choise = 0;
	switch (choise)
	{
	case 1:
		printf("清北\n");
		break;
	case 2:
		printf("c9\n");
		break;
	case 3:
		printf("985\n");
		break;
	case 4:
		printf("211\n");
		break;
	case 5:
		printf("双一流\n");
		break;
	case 6:
		printf("一本\n");
		break;
	case 7:
		printf("二本\n");
		break;
	case 8:
		printf("专科\n");
		break;
	}
	return 0;
}

image.png
成功运行

如果仅用来区分本科专科,可以这样写:

int main()
{
	int choise = 0;
	scanf("%d", &choise);
	switch (choise)
	{
	case 1:
	case 2:
	case 3:
	case 4:
	case 5:
	case 6:
	case 7:
		printf("本科\n");
		break;
	case 8:
		printf("专科\n");
		break;
	}
	return 0;
}

这样一来,无论是1~7哪个数字,直接进入之后就到printf打印“本科”那里了。
所以,break的作用其实是用来划分不同的分支的,而不是划分类型,不一定每个case后都要写break。

tips:最好在最后一个case语句上面加上一条break语句,避免之后再写case的时候和之前写的case有交叉,有break的话就可以直接把他们分开啦。

2.2.2 default 子句

在if语句中,如果我们输入了错误的值,可以用else来进行分支,那么在switch语句中我们如何解决这种输入错误的情况呢?
答案是:使用default子句
还是使用上文的栗子:

#include <stdio.h>

int main()
{
	int choise = 0;
	scanf("%d", &choise);
	switch (choise)
	{
	case 1:
	case 2:
	case 3:
	case 4:
	case 5:
	case 6:
	case 7:
		printf("本科\n");
		break;
	case 8:
		printf("专科\n");
		break;
	default:
		printf("输入错误\n");
	}
	return 0;
}

可见,只需要加上一个default的子句即可。而default和case这些子句都是没有顺序的,可以在switch语句里面随意调换顺序(一般情况下是栗子里面的顺序,方便代码的阅读)。

tips:在switch后加上一个default是一个好习惯,在其后再加上一个break就更好了。

2.2.3 switch语句最后的小练习:

请你计算m和n的值(时间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;
	}

正确答案的分割线(不要往下划啦,做完再划)


正确答案:
image.png
你算对了吗?

3、循环语句(循环结构)

在循环结构中,有三个语句:

  1. while
  2. for
  3. do while
    循环结构如下图:
    循环.png

3.1 while循环

3.1.1语法结构

while (exp)
	循环语句;

while后面的表达式是一个判断,和if的判断方法一样,不过while是一直判断,如果是真就执行后继续去判断表达式,直到表达式不是真(即==0)。
举个栗子:打印数字1-10:

int main()
{
	int a = 1;
	while (a <= 10)
	{		
		printf("%d ", a);
		a++;
	}
	return 0;
}

运行结果image.png
成功运行

3.1.2 while语句中的break和continue

  • break:直接结束while循环(永久终止循环)
  • continue:结束本次循环(直接进行下次循环)
3.1.2.1举个break的🌰:
#include <stdio.h>
int main()
{
	int a = 1;
	while (a <= 10)
	{
		
		if (a == 5)
			break;
		printf("%d ", a);
		a++;
	}
	return 0;
}

运行结果:
image.png
可以看出,在a加到5的时候,因为break语句直接就退出了循环,只打印了1 2 3 4 。

3.1.2.2举个continue的🌰:
int main()
{
	int a = 1;
	while (a <= 10)
	{	
		if (a == 5)
			continue;
		printf("%d ", a);
		a++;
	}
	return 0;
}

对刚刚的代码稍加改造,那么这个代码的结果是多少呢?

答案是:
image.png

1 2 3 4 之后就是死循环,和break不同,程序并没有结束,一直在跑,没有尽头。
为什么会出现这种情况呢?

我们在代码上进行一些标注:image.png

红色代表第五次while循环,粉色代表第六次while循环

可以看到,当a到达5的时候,一到continue便开始了无休止的循环,既没有结果也不会停止。

我们把a++放到前面再试一试:

int main()
{
	int a = 1;
	while (a <= 10)
	{		
		a++;
		if (a == 5)
			continue;
		printf("%d ", a);
	}
	return 0;
}

  • 运行结果:
    image.png

因为顺序的调换,变成了2打头,而5因为continue,跳过了,最后因为a++在printf前面的关系,直到打印11才停下来。

3.1.3利用getchar进行清理缓冲区

像scanf、getchar这类函数,是可以根据键盘上输入的字符来进行输入的,但是它们并不是直接打进程序里面去,而是先进到一个叫做输入缓冲区的地方,如图:
缓冲区.png

  • 那么在某些需要重复输入不同信息的情况下,缓冲区的信息可能还没被清理干净,就被读走了,就容易造成程序的bug。

  • 比如你输入一段数字,按了回车或者空格之后scanf读走了,之后再来个别的需要读取的函数,他不会自动的把缓冲区清零,而是直接把回车读走,也就是把\n读走,各种各样奇妙的bug就此诞生。

  • 既然缓冲区这么重要,那么如何清理它呢?

  • 我们可以利用while循环,加上一点点getchar的知识:

    • getchar是获取字符的关键字,通俗理解就是把字符读取走,拿走的意思。
  • 举个🌰:

#include <stdio.h>
int main()
{
	//字符类型的数组,定义密码,以后会详细讲
	char password[20] = { 0 };	

	printf("请输入密码--->");

	//%s表示打印字符串
	scanf("%s", password);

	printf("请确认密码--->");

	char input = 0;

	//下面这个while循环是重点,利用空语句让getchar不断的把回车之前的字符都读走,直到把回车读走,缓存区也就清空了
	while (getchar() != '\n')
	{
		;
	}
	//%c表示打印单个字符
	//这里用input=getchar();也可以
	scanf("%c", &input);
	if ('Y' == input)
		printf("确认成功\n");
	else
		printf("确认失败\n");
	return 0;
}

运行结果:
可以看到,不论是空格还是字母都不会出现因为缓存区不干净直接跳过输入的bug
image.png

3.2 for 循环

3.2.1语法结构

for(exp1;exp2;exp3)
	循环语句;

其中exp1用于初始化,exp2用于条件判断,exp3用于调整条件
如图所示:for流程.png

for和if语句一样,默认后面只能跟一个语句,如果想同时执行多条语句,则需要加大括号。

3.2.2for里面的break和continue

和while语句里面有异曲同工之妙:break仍是永久终止循环直接跳出去;continue仍是跳过本次循环。

3.2.3 for的循环控制变量

  1. 不可以在循环体内修改变量
  2. 建议for语句的取值采用“前闭后开区间”的写法,更加直观

3.2.4 for语句变种

  1. 省略for结构里的某一部分,或者全部省略
    1. 可能会导致某些bug
  2. 使用多个变量控制循环
    1. 如:for(x=0,y=0;x<2 && y<5;++x,y++)

3.3 do…while()循环

至少循环一次
语法结构:

do
	循环语句;
while(表达式);

4.goto语句

在C语言中,有一个语句比较特殊,它可以随意跳转到程序任意地方,这就是goto语句
虽然这个语句的功能非常强大,但是在实际使用过程中,由于其过于强大,想跳到哪就跳到哪,很容易出现程序运行出现死循环或者bug之类的故障。并且,一般情况下,其他几个分支循环语句就已经足够写程序用了,不需要用goto语句。
goto语句最常见的用处就是在深度嵌套的代码中,实现跳出。

写在最后

如果本文对您有帮助,可不可以给我一个小小的点赞呀❤~您的支持是我最大的动力。

博主小白一枚,才疏学浅,难免有所纰漏,欢迎大家讨论和提出问题,博主一定第一时间改正。

谢谢观看嘿嘿(๑•̀ㅂ•́)و✧~!

  • 19
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 13
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值