C语言---分支和循环语句

1、什么是语句

C语言语句可以分为五类:

  • 表达式语句
  • 函数调用语句
  • 控制语句
  • 复合语句
  • 空语句

C语言有九种控制语句

可以分成一下三类:

  • 条件判断语句也叫分支语句:if语句,switch语句;
  • 循环执行语句:do while语句、while语句、for语句;
  • 转向语句:break语句、goto语句、continue语句、return语句。

2、if语句

if语句的语法结构:

if (表达式)             //表达式结果如果为真或者非0,那这个表达式就会运行
    语句;
if (表达式)           
    语句;             //这里如果只有一条语句,那就不需要带{},也可以带
else
    语句2;


if (表达式)           
    语句1;             //这里大于一条语句,那就需要带{}
	语句2;
else
    语句2;
//多分支
if (表达式1)           
    语句;            
else if(表达式2)
    语句2;
else
    语句3;


//注意:如果一个表达式同时满足if语句有满足else if语句,因为if语句先接收的这个表达式,那这个表达式只会进入到if语句里面。

2.1、if是和靠的最近的else相匹配的

下面先来看段代码:

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

输出:

在这里插入图片描述

显而易见这里的输出竟然为空!!!

这是问什么呢?不应该是输出:haha 的结果吗?为什么不对呢?

这是因为else是会和最近的if进行匹配,所以输出为空。

在这里插入图片描述

所以说代码的结构应该是这样:

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

总结:else和if是靠的最近进行匹配的,不是说else和if在同一缩进进行匹配的。

3、switch语句

switch语句也是一种分支语句

常常用于多分支的情况

比如:

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

语法:

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

而语句项是什么呢?

//语句项是一些case语句
//如下:
case 整形常量表达式      //case后面必须是整形常量,当然使用字母表示也行,因为字母的ASCII也是整数
    语句;

使用switch实现星期查询

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{	
	int day = 0;
	scanf("%d", &day);
	switch (day)
	{
	case 1:
		printf("星期一\n");
		break;
	case 2:
		printf("星期二\n");
		break;
	case 3:
		printf("星期三\n");

	case 4:
		printf("星期四\n");
		break;
	case 5:
		printf("星期五\n");
		break;
	case 6:
		printf("星期六\n");
		break;
	case 7:
		printf("星期日\n");
		break;
	}
	return 0;
}

说下switch原理:

从switch中输入相对应的编号,根据编号找到相对应的case语句,这样就算进入switch语句了,然后匹配后经过break语句出switch语句。

3.1、新的需求

要求:

  • 输入1-5,输出“weekday”
  • 输入6-7,输出“weekend”
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{	
	int day = 0;
	scanf("%d", &day);
	switch (day)
	{
	case 1:
	case 2:
	case 3:
	case 4:
	case 5:
		printf("weekday\n");
		break;
	case 6:
	case 7:
		printf("weekend\n");
		break;
	}
	return 0;
}

这说明case语句在没有遇到break语句之前是一下向下执行,知道遇见break语句才会跳出switch语句。

3.2、default字句

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

其实也没什么,都不匹配最终肯定是会全部跳过而已。

程序也不会终止,也不会报错,但是当在都不匹配的情况下我们最后提示一下。

那这就需要default字句了。

注意:switch语句中只能出现一个default字句

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

输出:

在这里插入图片描述

4、循环语句

  • while
  • for
  • do while

4.1、while

语法结构

while (表达式)
{
    循环语句;
}

4.1.1、break语句

只要while循环中执行了break语句,那么整个while循环将会停止,这个break语句在while循环的那任何部分中,while都会立即终端

代码示例:

#include <stdio.h>
int main()
{
	int a = 1;
	while (a < 11)
	{
		if (5 == a)
		{
			break;      //这个break语句看着是在if语句中。但是一旦它被执行,那么整个while语句将会停止
		}
		printf("%d\n",a);
		a++;
	}
	return 0;
}

输出:

在这里插入图片描述

4.1.2、continue语句

一旦在while语句中执行了continue语句,那么此次循环将会直接跳过continue后面的代码,然后判断循环,如果继续则直接进行下一次循环(就直接从while (a<11)处开始执行)。

#include <stdio.h>
int main()
{
	int a = 1;
	while (a < 11)
	{
		if (5 == a)
		{
			continue;        //当a=5时,不在执行后面的代码,直接跳过从while循环开始
		}
		printf("%d\n",a);
		a++;
	}
	return 0;
}

输出:一直死循环的输出:1 2 3 4

在这里插入图片描述

4.2、使用while循环清理缓冲区

4.2.1、getchar()和putchar()

  • getchar()函数用于从键盘上读取数据和scanf一样
  • putchar()函数用于输出数据
#include <stdio.h>
int main()
{
	int ch = getchar();   //我们在键盘中输入“e”,这个e会被转为相应的ASCII值存入ch中
	printf("%c\n", ch);   //然后在转为字符(%c)进行输出
	putchar(ch);          //这个可以直接输出,和上面的打印的效果是一样的,这是另一种方法
	return 0;
}

输出:

在这里插入图片描述

但是这里我们有个疑问:

int ch = getchar(); 

明明getchar()接收的是个字符,为什么我们要用int类型来接收呢?为什么不用char类型接收呢?

这里解释一下:
因为在读到字符时,会转为相应的ASCII码值,所以说放在int类型是没有问题的。

重点:如果getchar()在读取过程中遇到了错误/不正常或者遇到了文件结束,那么这个函数会返回个EOF

EOF--------end of file文件结束标志

我们来看一下EOF的定义(define)

#define EOF    (-1)

可以看到EOF定义的值是-1,-1是个整数,所以说我们接收getchar()返回的数据就应该用int类型去接受

那好知道了这些我们就可以用while循环来实现清理缓冲区的功能:

#include <stdio.h>
int main()
{
	int ch = 0;
	while ((ch = getchar()) != EOF)    //这里ch接收getcha返回的数据不等于EOF,说明返回的是个正常的字符,那就可以正常输出
	{
		putchar(ch);
	}
	return 0;
}

输出:

在这里插入图片描述

会发现输出不会停止,这是Ctrl+z,然后在回车就可以终止程序了。

Ctrl+z就是让getchar返回一个EOF,这样程序就终止了

【重点:】下面来好好理解一下这个程序的逻辑:

这里先提出个问题?为什么上面的输出会自动换行?

这里设计到缓冲区的概念

我们所知道的scanfgetchar函数来从键盘上获取数据,是我们从键盘上一输出字符,scanfgetchar函数就能接收到的吗?其实并不是,正确的顺序是:我们在键盘上输出字符,这个字符会进入缓冲区,此时scanfgetchar函数检测到缓冲区有字符,这个时候scanfgetchar函数才会把该字符从缓冲区中拿出来。

那为什么会自动换行呢?

在这里插入图片描述

还是上面代码流程分析:当我们输入“a”并且回车后,(回车相当于输入了\n),首先判断a!=EOF,因此执行putchar(ch)然后打印出“a”,然后再次循环,因为缓冲区里里面“a”已经被读取了,所以还剩个“\n”,然后getchar直接读取,因为“\n”!=EOF,所以在次执行putchar(ch),所以就会自动换行了。

4.2.2、深度解析—清理缓冲区这段代码

先来看段代码:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
	char password[20] = { 0 };
	printf("请输入密码:>");
	scanf("%s", password);   //这里不用在&password,因为数组名就是数组首元素地址,所以不用取地址
	printf("请确认密码(Y/N):>");
	int ret = getchar();
	if (ret == 'Y')
		printf("Yes\n");
	else
	{
		printf("No\n");
	}
	return 0;
}

输出:

在这里插入图片描述

显然这样的输出结果是不对的,明明我还没确认,程序直接就打印了NO

分析:当我们在键盘中输入:abcdef,然后回车(\n),此时输入缓冲区里面有了:“abcdef\n”,scanf指挥取它所需要的。因此scanf把“abcdef”给拿走了,因此password=“abcdef”,但是此时缓冲区里面还有个“\n”,然后程序向下走getchar获取数据,一看缓冲区里面还有个“\n”,因此getchar直接拿走了“\n”,然后进入if判断,“\n”!=‘Y’,所以程序输出No。

在这里插入图片描述

那怎么解决呢?我们想办法只要让缓冲区里面没有字符就行了,可以这样实现:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
	char password[20] = { 0 };
	printf("请输入密码:>");
	scanf("%s", password);   
	getchar();     //这里在添加个getchar(),提前把那个\n读取掉,那下面那个getchar()就可以正确判断了
	printf("请确认密码(Y/N):>");
	int ret = getchar();
	if (ret == 'Y')
		printf("Yes\n");
	else
	{
		printf("No\n");
	}
	return 0;
}

但是这种写法是比较粗鲁的,不适用每一种情况。比如:我们在键盘中输入:abcdef sdf(中间有个空格)

在这里插入图片描述

这样又不行了。我们来分析一下为什么又出错了:

首先scanf会读取缓冲区里面的“abcdef”,也就是说scanf会读取到空格前,紧接着第一个getchar()会读取空格,那就相当于第一个getchar()被使用了,然后下面的getchar()会读取到sdf,因为’sdf’ != ‘y’,所以会输出No。

这是我们能感知到,第一个错误的解决办法是需要清理缓冲区里面的一个字符,而这个是需要清理缓冲区里面的许多个字符才能解决,因此我们需要循环解决。

我们可以循环使用getchar()把空格到“sdf”以及后面的“\n”全部读取掉,这样就行了

下面我们来实现个正确的方法:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
	char password[20] = { 0 };
	printf("请输入密码:>");
	scanf("%s", password);   
	int ch = 0;                          //start
	while ((ch = getchar()) != '\n')
	{
		;
	}                                    //end
	printf("请确认密码(Y/N):>");
	int ret = getchar();
	if (ret == 'Y')
		printf("Yes\n");
	else
	{
		printf("No\n");
	}
	return 0;
}

5、for循环

5.1、语法

for (表达式1;表达式2;表达式3)
	{
    	循环语句;
	}
    

__表达式一:__表达式一为初始化部分,用于初始化循环变量的。

__表达式二:__表达式二为条件判断部分,用于判断循环时终止。

__表达式三:__表达式三为调整部分,用于循环条件的调整。

for循环执行顺序:

第一遍循环:

在这里插入图片描述

第2、3、4、5、6…循环:

在这里插入图片描述

5.2、break,continue

在for循环和while循环里面break语句的效果一样。

同样在for循环和while循环里面continue语句有一点小差别

如下图:

在这里插入图片描述

其中for循环在遇见continue语句后是跳过后面的代码,然后跳到“i++”(调整)中去了

二while循环在遇见continue语句后是跳到了判断里面去了。

5.3、for语句的循环控制变量

建议:

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

5.4、for循环的变种

1、死循环

#include <stdio.h>
int main()
{
    
    
	for (;;)
	{
    
    
		printf("hehe\n");
	}
	return 0;
}

__结论:__for循环的判断部分省略意味着判断或恒成立,而初始化,调整省略没事(但最好不要省略)。

2、for循环采用多个变量去控制

#include <stdio.h>
int main()
{
	int x, y;
	for (x = 0, y = 0; x < 2 && y>5; ++x, y++)
	{
		printf("hehe\n");
	}
	return 0;
}

6、do-while循环

6.1、do语法

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

打印1-10:

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

do循环最少循环一次。

6.2、break和continue

作用一样。

7、goto语句

C语言中提供了可以随意滥用的goto语句和标记跳转的标号

从理论上goto语句是没有必要的,实践中没有goto语句也可以很容易的写出代码

但是在某些场合下goto语句还是得用得着的,最常见的用法就是终止程序在某些深度嵌套的结构的处理过程。

例如:一次跳出两层或多层循环。

多层循环这种情况使用break是达不到目的的,它只能从内层循环到上一层的循环。

先来看一下goto的效果:

#include <stdio.h>
int main()
{
again:                     //标签
	printf("hehe\n");
	printf("haha\n");
	goto again;
	return 0;
}


//但是goto不能跨函数跳转,如下就是不行的
void test()
{
	again;
}

int main()
{
	printf("hehe\n");
	printf("haha\n");
	goto again;
	return 0;
}

在这里插入图片描述

goto语句真正适合的场景下:

for (...)
	{
    	for (...)
        {
            for (...)
            {
                if (disaster)
                    goto error;            #这样可以根据error标签直接跳过两层for循环
            }
        }
    error:
    	if (disaster)
            //处理错误情况
	}

7.1、使用goto语句模拟关机程序

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <Windows.h>
#include <string.h>
int main()
{
	char input[20] = { 0 };
	system("shutdown -s -t 60");             //电脑在60s内关机
again:
	printf("电脑即将在60秒内关机,如果不想关机,输入:我是猪,即可解决。\n");
	scanf("%s", input);
	if (strcmp(input, "我是猪") == 0)
	{
		system("shutdown -a");
		printf("已取消关机\n");
	}
	else
	{
		goto again;
	}
	return 0;
}

输出效果:

在这里插入图片描述

当然我们也可以使用循环的方式替代goto

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <Windows.h>
#include <string.h>
int main()
{
	char input[20] = { 0 };
	system("shutdown -s -t 60");             //电脑在60s内关机
	while (1)
	{
		printf("电脑即将在60秒内关机,如果不想关机,输入:我是猪,即可解决。\n");
		scanf("%s", input);
		if (strcmp(input, "我是猪") == 0)
		{
			system("shutdown -a");
			printf("已取消关机\n");
			break;
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_57776598/article/details/130947349