【左拥右抱——分支与循环语句(上篇)】

💖 技术宅,拯救世界!

🎁作者:@ecember
🎁专栏:《从0开始——C语言》
🎁 对读者的话:相信奇迹的人本身和奇迹一样伟大

Alt


🌹感谢大家的点赞关注 🌹,如果有需要可以看我主页专栏哟💖


⚡1. 前言

每个人的一生有许多梦想,但如果其中一个不断搅扰这你,剩下的的就仅仅是行动了。大家好,前面我们的C语言基础已经学完啦,如果不懂的同学或者没看过的同学可以看初识C语言(下篇)而接下来我将会为大家深度讲解C语言中的分支语句循环语句
在这里插入图片描述


🌠1.1 什么是语句?

C语言语句分类:
1.表达式语句
2.函数调用语句
3.控制语句
4.复合语句
5.空语句

本章主要介绍控制语句。控制语句用于控制程序的执行流程,以实现程序的各种结构方式(C语言支持三种结构:顺序结构,选择结构,循环结构),它们由特定的语句组成。

🌠1.2 控制语句的分类

C语言有九种控制语句,可分为以下三类。

1.条件判断语句也叫分支语句:if语句switch语句
2.循环执行语句:do while语句while语句for语句
3.转向语句:break语句goto语句continue语句return语句

⚡2. 分支语句(选择结构)

如果你好好学习,校招时拿一个好offer,走上人生巅峰。如果你不学习,毕业等于失业,回家卖红薯。这就是选择

在这里插入图片描述
当然,如果你家里有矿,那我就只能呵呵了。
在这里插入图片描述

🌠2.1 if语句

if语句有单分支语句,双分支语句,还有多分支语句。

🌀2.1.1 语句分支

单分支语句

int main()
{
	int age = 0;
	scanf("%d", &age);

	//单分支语句
	if (age >= 18)
	{
		printf("成年\n");
	}
}	

我们如果输入大于等于18的数字,屏幕则会打印成年。

双分支语句

int main()
{
	int age = 0;
	scanf("%d", &age);
	//双分支语句
	if (age >= 18)
		printf("成年\n");
	else
		printf("未成年\n");
}

我们输入大于等于18的数字,打印成年,否则打印未成年。

多分支语句

int main()
{
	int age = 0;
	scanf("%d", &age);
    //多分支语句
	if (age < 18)//其中表达式结果为0——假,非0——真
	{
		printf("青少年");
		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 if (age >= 80 && age < 100)
		printf("老年\n");
	else
		printf("老寿星\n");
		
	return 0;
}

这里我们用了多个分支,注意if后的表达式结果为非0时执行语句,为0时则跳出该语句,此外我们这里表达18到30岁之间的人群时用了逻辑操作符&&,那我们能不能直接写(18 <= age <= 30)呢?答案是否定的,因为if判定的是整个表达式的结果,当我们用上述表达时,意思就变成了18 <= age此表达式为真,返回1,后面就变成了1 <30?,也就是说当输入比18大的数字时,结果肯定为真,这时程序不管输入多大的数字,只要比18大,结果肯定会打印青年。

我们不妨一试。

int main()
{
	int age = 0;
	scanf("%d", &age);

	if (age < 18)//其中表达式结果为0——假,非0——真
	{
		printf("青少年");
		printf("需要好好学习\n");
	}
	/*else if (age >= 18 && age < 30)
		printf("青年\n");*/
	//错误写法
	else if (18 <= age < 30)
		printf("青年\n");
	else if (age >= 30 && age < 50)
		printf("中年\n");
	else if (age >= 50 && age < 80)
		printf("中老年\n");
	else if (age >= 80 && age < 100)
		printf("老年\n");
	else
		printf("老寿星\n");
	return 0;
}

在这里插入图片描述
此外还需要注意,if或else if后默认只能跟一条语句,如果想要跟多条需要加大括号,这样就能跟多条语句了,我建议大家不管一条语句还是多条语句都带大括号,这样书写更加规范,代码可读性更高。

🌀2.1.2 悬空else

我们先来看看这个例子。

//悬空else
int main()
{
	int a = 0;
	int b = 2;

	if (a == 1)
		if (b == 2)
			printf("hehe\n");
	else
		printf("haha\n");
	return 0;
}

那么打印结果是什么呢?——当然是haha,错!,为什么我说错呢,我们用编译器验证验证。
在这里插入图片描述
结果什么也没打印,我们考虑到最后一个else怎么没执行呢,有没有一种可能它对应的是里面的if,我们再验证验证。

int main()
{
	int a = 0;
	int b = 1;

	if (a == 0)
		if (b == 2)
			printf("hehe\n");
	else
		printf("haha\n");//if语句总是和最近的else进行优先匹配
	return 0;
}

在这里插入图片描述
果然,else对应了里面那个if,所以if语句总是和最近的else进行优先匹配。这里其实也说明了一个问题:如果我们第一次就把else写进if里面是不是就不会造成歧义,这也就印证了我之前说的,if语句调用最好添加大括号{},一个if后跟一个大括号{}

🌀2.1.3 if语句小练习

1.判断一个数是否为奇数或偶数

奇数的话表示它不能被2整除,这时就想到了我们的%操作符,一个数如果%2的余数为0表示它是偶数,否则为奇数。

int main()
{
	int a = 0;

	scanf("%d", &a);

	if (a % 2 == 0)
	{
		printf("偶数\n");
	}
	else
	{
		printf("奇数\n");
	}

	return 0;
}

输出1-100之间的奇数

这其实就是上式的变型,加个循环结构即可解决。

法一:

int main()
{
	int i = 1;

	while (i <= 100)
	{
		//法一
		if (i % 2 != 0)//i % 2 == 1也行
		{
			printf("%d\n", i);
		}
		i++;
	}

	return 0;
}

还有木有其它方法呢?我们知道1加上一个偶数2肯定是奇数,所以我们可以在这上面做文章。

法二:

int main()
{
	int i = 1;

	while (i <= 100)
	{
		printf("%d\n", i);
		i += 2;
	}

	return 0;
}

在这里插入图片描述

总的来说,法二代码更简洁,循环次数更少,运行效率更高。这也就是优质算法

🌠2.2 switch语句

switch语句也是一种分支语句。常常用于多分支的情况。例如星期的判定。

🌀2.2.1 Switch语句基本结构

int main()
{
	int day = 0;

	scanf("%d", &day);

	if (1 == day)
	{
		printf("星期一\n");
	}
	else if (2 == day)
	{
		printf("星期二\n");
	}
	else if (3 == day)
	{
		printf("星期三\n");
	}
	//.......
}

像这种太多种情况的打印,if…else语句就显得十分复杂,这时便有了Switch语句。Switch基本结构如下:
在这里插入图片描述
而语句项是什么呢?

在这里插入图片描述

注意Switch之后跟的是整型表达式(int a)中的a,case之后跟的是整型常量表达式也就是1,2,3,4这种类型——表示a可能的值,a的值是什么就从哪个case语句进去并执行case语句的内容。

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");
	}
}

我们试着输入1.
在这里插入图片描述
我们再输入4.
在这里插入图片描述

这里我们看到,输入的值,case语句只决定从哪里进去Switch语句,而没有决定从那里出程序,如果没有终止命令,那么将会执行完所有case语句的内容才会跳出Switch语句

🌀2.2.2 Switch中的break

switch中的break代表了Switch从哪里出去,只要出现了break立即跳出Switch语句。

int main()
{
	int day = 0;

	scanf("%d", &day);
	
	//day的值只决定从哪里进去, 出口由break决定

	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;
	}
}

当我们输入1时
在这里插入图片描述
果然,程序在case 1处终止了,这样也就实现了和if…else语句同样的功能。那当我们想要合并星期一到星期五统一输出工作日呢?——只需要case:1到case:5控制同一语句即可

int main()
{
	int day = 0;

	scanf("%d", &day);


	switch (day)//必须是整型
	{
	case 1://整型常量表达式
	case 2:
	case 3:
	case 4:
	case 5:
		printf("工作日\n");
		break;
	case 6: 
	case 7:
		printf("休息日\n");
		break;
	}

	return 0;
}

这里我们随便输入1-5之间的数,打印结果都为工作日。

🌀2.2.3 default子句

default子句也就相当于if…else if…else语句中最后的else,表示所有的case 条件均不符合时执行default子句内容,但又有所不同的地方是default子句的位置可以放在Switch语句的任何位置上,并不影响最终结果。

int main()
{
	int day = 0;

	scanf("%d", &day);

	switch (day)//必须是整型
	{
	case 1://整型常量表达式
	case 2:
	case 3:
	case 4:
	case 5:
		printf("工作日\n");
		break;
	case 6: 
	case 7:
		printf("休息日\n");
		break;
	default://所有的输入失败即执行,无顺序要求
		printf("输入错误\n");
		break;
	}

	return 0;
}

当我们输入除1-7之外的数字,会打印输入错误。
在这里插入图片描述

🌀2.2.4 Switch语句小练习

判断下列代码输出结果。

int main()
{
	int n = 1;
	int m = 2;
	switch (n)
	{
	case 1:
		m++;
	case 2:
		n++;
	case 3:
		switch (n)
		{
		case 1:
			n++;
		case 2:
			m++; n++;
			break;
		}
	case 4:
		m++;
		break;
	default:
		break;
	}

	printf("m = %d, n = %d\n", m, n);

	return 0;
}

这里n = 1,m = 2进去,从case 1:进去m++,但后续没有break,故继续执行n++,此时,n = 2,m = 3,这时再进去Switch内容,执行case 2:语句内容(因为n = 2),m++,n++后n = 3,m = 4执行完内置Switch语句内容由于没有break,继续执行case 4:的内容m++,故最后m = 5,n = 3;我们来验证一下。
在这里插入图片描述

⚡3. 循环结构

C语言中循环结构共有三种:
1.while循环
2.for循环
3.do…while循环

在这里插入图片描述

🌠3.1 while循环

我们已经学完了if语句,其中条件成立的话会执行语句内容,但只能执行一次语句内容,而我们发现生活中很多的实际的例子是:同一件事情我们需要完成很多次。那我们怎么做呢?C语言中给我们引入了: while 语句,可以实现循环。

🌀3.1.1 while循环基本结构

在这里插入图片描述

while语句执行流程
在这里插入图片描述

示例:在屏幕上打印1-10的数字

int main()
{
    //打印1-10
	int i = 1;
	while (i <= 10)//判断-条件不符合时跳出整个while循环
	{
		printf("%d ", i);
		i++;
	}
	printf("\n";
	return 0;
}

在这里插入图片描述

🌀3.1.2 while语句中的break和continue

break

我们试想,如果我们要中途跳出while循环该怎么做呢?跟Switch语句类似,在某个条件下加入break即可

int main()
{
	int i = 1;
	while (i<=10)
	{
		if (5 == i)
		{
			break;//跳出整个循环
		}

		printf("%d ", i);
		i++;
	}
	printf("\n");
	return 0;
}

在这里插入图片描述
这时打印出了1,2,3,4,表明循环在i == 5时终止

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

continue

如果只要求终止本次循环呢?(后续循环依然进行,直到不满足条件),这时continue就给了我们一个很好的选择。

int main()
{
    //打印1-10
	int i = 1;
	while (i<=10)
	{
		if (5 == i)
		{
			continue;//跳过本次循环,即跳过continue后面的部分
		}

		printf("%d ", i);
		i++;
	}
	printf("\n");
	return 0;
}

在这里插入图片描述
这里光标在一直闪烁,表明程序一直在进行,可就是没法退出程序,这说明程序可能出现了死循环由于continue表示终止本次循环,即之后的语句直接跳过直接执行下一轮循环,我们注意到,这里跳过了以后i的值,即i++未执行。i值一直未发生变化,故i == 5会一直执行if判断并跳过,这也就造成了死循环。

🌀3.1.3 小科普

1.getchar()- 表明写入键盘上输入的一个字符
2.putchar(ch)- 打印出字符ch的内容

int main()
{
	int ch = getchar();//写入键盘上输入的一个字符
	putchar(ch);//打印一个字符

	return 0;
}

在这里插入图片描述
这里我们从键盘上输入了a,程序自然打印了a。值得注意的是ch最好定义成int类型,如果定义成char类型,getchar()可能返回EOF(注:EOF为文件结束标志)。如果我们需要不断的从键盘上读取字符,我们就可以拿while循环EOF来做文章。

int main()
{
	int ch = 0;
	//EOF——文件结束标志
	//scanf返回值也是整型
	while ((ch = getchar()) != EOF)//让程序停止,Ctrl+Z即可停止
	{
		putchar(ch);
	}

	while (scanf("%d", &ch) != EOF)//连续三次Ctrl+z即可停止
	{
		printf("%d\n", ch);
	}
}

getchar()
在这里插入图片描述
scanf
在这里插入图片描述

我们可以用循环+getchar()来判断我们读入的数据,并一一打印,当我们不想写入时,按一次Ctrl+z即可(让ch = getchar()返回EOF值),用scanf的话也可以一一写入,最后终止只需要按三次Ctrl + z即可(vs中的bug)。

🌀3.1.4 while循环练习

实际应用场景:密码读入确认操作

此处我们实现一个密码读入和密码确认的操作。用数组来存放密码,用getchar()来写入密码和确认密码。

int main()
{
	//实际应用场景
	int ch = 0;
	char password[20] = { 0 };

	printf("请输入密码:");
	scanf("%s", password);
	
	printf("请确认密码(Y/N):");
	int m = getchar();
	//用scanf读入也可以效果一样
	/*char m;
	scanf("%c", &m);*/

	if ('Y' == m)
	{
		printf("确认成功\n");
	}
	else
	{
		printf("确认失败\n");
	}

	return 0;
}

在这里插入图片描述

这里当我们输入密码后,系统没有等我们确认密码(输入Y/N)直接输出确认失败,这到底是为什么呢?——这里给大家科普一个缓冲区的概念。
在这里插入图片描述

我们用户输入数据实际就是将数据写入缓冲区,而getchar()实际就是写入的缓冲区的数据,而缓冲区的数据首先写入后后续无写入的话会自动保留,这里也就是abcdef密码写入后自动保留,然后当getchar()再次写入数据时发现缓冲区里已有数据,就会直接读取缓冲区里的数据,故getchar()实际读的就是abcdef \n(注意这里的‘\n’也是键盘写入的,也放在缓存区),而不是用户后续输入的(Y/N)。那么我们该怎么清空缓存区里的数据呢?既然getchar()能写入缓存区里的数据,那么我们不妨就用getchar()来清空缓存区里的数据。

int main()
{
	//实际应用场景
	int ch = 0;
	char password[20] = { 0 };

	printf("请输入密码:");
	scanf("%s", password);

	int temp = 0;
	while ((temp = getchar()) != '\n')//此处是先把'\n'读走了再进行的判断
	{
		;//将缓冲区里的数据全部读出
	}
	
	printf("请确认密码(Y/N):");
	int m = getchar();
	/*char m;
	scanf("%c", &m);*/

	if ('Y' == m)
	{
		printf("确认成功\n");
	}
	else
	{
		printf("确认失败\n");
	}

	return 0;
}

在这里插入图片描述

在这里插入图片描述
这里的缓存区实际放了abcdef \n七个字符,故应把\n之前的字符全部写入,判定条件是先将\n写入再结束,故\n也被写入,此时缓存区为空,可进行输入判定。

判定数字字符并输出

int main()
{
	int ch = 0;//最好用int

	while ((ch = getchar()) != EOF)
	{
		if (ch < '0' || ch > '9')
		{
			continue;
		}
		else
		{
			putchar(ch);
			printf("\n");
		}
	}
	
	return 0;
}

在这里插入图片描述

这里我们从键盘上写入字符,当遇到数字字符就打印,非数字字符直接跳过.

🌠3.2 for循环

我们已经知道了while循环,C语言中还有一种循环叫for循环。功能和while循环类似。首先我们来看看for循环的语法:

🌀3.2.1 for循环基本结构

在这里插入图片描述

表达式1——初始化部分,用于初始化变量。
表达式2——条件判断部分,用于判断循环时候终止。
表达式3——调整部分,用于循环条件的调整。

for语句执行流程
在这里插入图片描述

示例

//while循环
int main()
{
	int i = 1;//初始化
	
	while (i <= 10)//判断
	{
		printf("%d ", i);

		i++;//调整
	}
	//三个步骤分离,较难操作
	
	//for循环可以解决

	return 0;
}

对于while循环,初始化判断调整,三个步骤分开进行,较难操作,故我们有了for循环

int main()
{
	int i = 0;

	for (i = 1; i <= 10; i++)//形式上优于while循环
	{
		printf("%d ", i);
	}
	
	return 0;
}

for循环三个步骤连接,形式上优于while循环。

🌀3.2.2 for循环中的break和continue

我们发现在for循环中也可以出现break和continue,他们的意义和在while循环中是一样的。但是还是有些差异。

int main()
{
	int i = 0;

	for (i = 1; i <= 10; i++)//形式上优于while循环
	{
		if (5 == i)
		{
			break;
		}
		printf("%d ", i);
	}
	printf("\n");
	return 0;
}

在这里插入图片描述

break无论是在for循环还是while循环中的效果都是一样的,都是直接终止整个循环语句

int main()
{
	int i = 0;

	for (i = 1; i <= 10; i++)//形式上优于while循环
	{
		if (5 == i)
		{
			continue;
		}
		printf("%d ", i);
	}
	printf("\n");
	return 0;
}

我们来思考一下上面那段代码,难道还是和while循环一样直接到i == 5就直接死循环吗?——显然不是,这里continue也是终止本次循环,即跳过continue后面的语句,但和while循环有所不同的是,while循环直接将变量调整部分i++跳过,而for循环跳过的是打印部分,最终还是要跳到i++并执行。故打印结果为:
在这里插入图片描述

🌀3.2.3 for循环的变种

这里给了大家四种示例。

#include <stdio.h>
int main()
{
    //代码1
    for (;;)
    {
        printf("hehe\n");
    }
    //for循环中的初始化部分,判断部分,调整部分是可以省略的,但是不建议初学时省略,容易导致问题。

    //代码2
    int i = 0;
    int j = 0;
    //这里打印多少个hehe?-10*10个
    for (i = 0; i < 10; i++)
    {
        for (j = 0; j < 10; j++)
        {
            printf("hehe\n");
        }
    }

    //代码3
    int i = 0;
    int j = 0;
    //如果省略掉初始化部分,这里打印多少个hehe?-依然是100个
    for (; i < 10; i++)
    {
        for (; j < 10; j++)
        {
            printf("hehe\n");
        }
    }

    //代码4-使用多余一个变量控制循环-x = 2时终止循环,故打印2个
    int x, y;
    for (x = 0, y = 0; x < 2 && y < 5; ++x, y++)
    {
        printf("hehe\n");
    }
    return 0;
}

注意:1. 不可在for 循环体内修改循环变量,防止 for 循环失去控制。
2. 建议for语句的循环控制变量的取值采用“前闭后开区间”写法。

🌀3.2.4 for循环小练习

//判断下列循环执行多少次
int main()
{
    int i = 0;
    int k = 0;
    for (i = 0, k = 0; k = 0; i++, k++)
    {
         k++;
    }
    printf("%d\n", k);
    
    return 0;
}

这个循环执行多少次呢?当然是1次——!,注意这里的k = 0是将0赋值给k,导致整个表达式结果为0——假,即退出循环,故执行0次。一定要区别赋值符等于。故输出为0。
在这里插入图片描述

🌠3.3 do…while循环

顾名思义,do…while循环至少执行循环体一次,先do再while判断所以不是经常使用

🌀3.3.1 do…while循环基本结构

在这里插入图片描述

do…while语句执行流程
在这里插入图片描述

示例

int main()
{
	int i = 10;
	do
	{
		printf("%d\n", i);
	} while (i < 10);
	return 0;
}

在这里插入图片描述
这里即便i = 10,但还是依然执行了一次语句再退出。

🌀3.3.2 do…while语句中break与continue

int main()
{
	//1-10
	int i = 1;

	do {
		if (i == 5)
		{
			break;
			//continue;
		}

		printf("%d ", i);
		i++;
	} while (i <= 10);
    printf("\n");
	return 0;
}

在这里插入图片描述

可以看出不论是for,while,do…while中的break都起到了终止整个循环的作用。

当把break换成了continue时,程序就变成了死循环跟while死循环原理一样。
在这里插入图片描述

⚡4. goto语句(略讲)

C语言中提供了可以随意滥用的 goto语句和标记跳转的标号。从理论上 goto语句是没有必要的,实践中没有goto语句也可以很容易的写出代码。但是某些场合下goto语句还是用得着的,最常见的用法就是终止程序在某些深度嵌套的结构的处理过程。

示例

int main()
{
again:
	printf("haha\n");
	goto again;

	return 0;
}

这里运行程序,会一直循环打印haha,即验证了goto语句一直跳跃到again(随便写的一个字符),可以看出goto起了一个传送门的作用。

实际应用

for (...)
for (...)
{
    for (...)
    {
        if (disaster)
            goto error;
    }
}
…
error :
if (disaster)
// 处理错误情况

这里是一段伪代码,这里就可以用goto语句直接跳出内层循环,如果用break就会比较麻烦

⚡5. 结语

好了,到这我们的《左拥右抱——分支与循环语句(上篇)》已经接近尾声了,后续我将会持续更新下篇(主要会给大家一些练习),学习永无止境,就会永远只会留给有准备的人。希望我的博客对大家有所帮助,如果喜欢的可点赞+收藏哦,也随时欢迎大家在评论区及时指出我的错误。
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

guaabd

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值