「地表最强」C语言(五)循环语句

环境:CLion2021.3;64位macOS Big Sur


地表最强C语言系列传送门:
「地表最强」C语言(一)基本数据类型
「地表最强」C语言(二)变量和常量
「地表最强」C语言(三)字符串+转义字符+注释
「地表最强」C语言(四)分支语句
「地表最强」C语言(五)循环语句
「地表最强」C语言(六)函数
「地表最强」C语言(七)数组
「地表最强」C语言(八)操作符
「地表最强」C语言(九)关键字
「地表最强」C语言(十)#define定义常量和宏
「地表最强」C语言(十一)指针
「地表最强」C语言(十二)结构体、枚举和联合体
「地表最强」C语言(十三)动态内存管理,含柔性数组
「地表最强」C语言(十四)文件
「地表最强」C语言(十五)程序的环境和预处理
「地表最强」C语言(十六)一些自定义函数
「地表最强」C语言(十七)阅读程序

五、循环语句

5.1 while

5.1.1 getchar()在循环中的使用

首先明确一点,程序读取键盘键入的数据时,并非与键盘直接相连,在程序与键盘之间存在一个缓冲区,每次键盘键入的数据会放入缓冲区,程序每次会从缓冲区中取数据;若缓冲区为空,则程序会等待键盘键入数据到缓冲区,然后从缓冲区读取数据。回车会以’\n’的形式存在缓冲区中。
getchar()一次只能获取一个字符,与其对应的putchar()一次只能打印一个字符;与scanf()不同的是,scanf()遇到空格、回车、制表符的时候会停止读取数据,即使这三者后边仍然有数据,也无法读取;
而getchar()会将空格、回车、制表符也作为数据读入,直到遇到文件结束标志EOF(end of file:文件结束标志),或者键入ctrl z才停止读取数据。
下面举一个简单的例子,输入密码后要删除一个文件,确定的话输入’Y’,否则删除失败:

	char password[20] = { 1 };//第一项为1,其余为0
	printf("please input the psw:");
	scanf("%s", password);//数组名本身就是地址,不需取地址&		
	//此时缓冲区有键入的数据和\n,scanf会取走数据,留下\n
	printf("are u sure to delete?(Y/N):");
	int ch = getchar();//此时缓冲区有\n,直接被getchar读取
	if (ch == 'Y')
		printf("sunccess\n");
	else
		printf("fail");

无论输入什么,其实都不会让你有确认的机会(即不会让你输入Y或者其他),会直接返回fail这个结果:
在这里插入图片描述
以上边的输入为例,说明一下为什么是这个结果以及怎么解决:
在这里插入图片描述
如图,当输入密码后,按下回车键,scanf()就开始从缓冲区中读取数据,此时缓冲区中的数据有 ‘a’ ‘s’ ‘d’ ‘4’ ‘5’ ‘6’ ‘4’ ‘6’ ‘.’ ‘.’ ‘\n’,\n就是按下的回车键,以这个形式存放在缓冲区。而scanf不会读取回车、空格、制表符,因此读取后,缓冲区会留下’\n’。当执行getchar()的时候,getchar()会读取这个’\n’,存入变量ch,显然不等于’Y’,因此执行else语句。
想要解决这个问题,我们需要将缓冲区的空格、回车、制表符都拿出来,以防影响后续输入。

	char password[20] = { 1 };//第一项为1,其余为0
		printf("please input the psw:");
		scanf("%s", password);//数组名本身就是地址,不需取地址&		此时缓冲区有键入的数据和\n,scanf会取走数据,留下\n
								//scanf不读取回车,空格,制表符
		printf("please confirm the psw(Y/N):");
		//清理缓冲区中的多个字符
		int tmp = 0;
		while ((tmp = getchar()) != '\n')
		{
		//	只要不是\n,就全部用getchar()接收,接收后什么的不用做。
		// 当最后一次遇到\n时,已经被接受了并且传给了tmp,此时说明缓冲区已空;
		}
		int ch = getchar();//此时缓冲区有\n,直接被getchar读取
		if (ch == 'Y')
			printf("sunccess\n");
		else
			printf("fail");

改进后可以看到,测试的字符串中虽然有空格等字符,但仍然不影响结果:
在这里插入图片描述

5.1.2 break与continue

break:终止循环;
continue:跳过本次循环中,continue后边的代码,回到判断出判断是否继续循环。
测试:键入字符,若是数字,则打印,否则不打印:

	int ch = 0;
	while ((ch = getchar()) != EOF)
	{
		if (ch < '0' || ch > '9')
			//break;
			continue;
		putchar(ch);
	}

break结果:
在这里插入图片描述

continue结果:
在这里插入图片描述

对比上边的结果:当遇到非数字时,break直接跳出了while循环;而continue跳过了本次循环后边的部分,即printf()没有被执行,然后开始下一次循环。

5.2 for

首先两点建议:

  • 不在循环体内调整循环变量:(极易产生错误)
  • 循环控制变量采用前闭后开的写法

5.2.1 break与continue

前面在while中已经介绍过二者的用法,但是还是不够直观,这里采用一种更为直观的方法:

	int i = 0;
	for (i = 1; i <= 10; i++)
	{
		if (i == 5)
			//break;
			continue;
		printf("%d ", i);
	}

break结果,到5直接跳出循环:
在这里插入图片描述

continue结果,跳过5这一次循环,继续第六次循环:
在这里插入图片描述

5.2.2 for循环的其他形式

  1. 表达式的省略
    1.1三个部分都可以省略,但是判断部分的省略会导致死循环,谨慎使用:
	for (; ;)
	{
		printf("123 ");
	}

运行结果:
在这里插入图片描述

         1.2省略初始化:

	int i = 0;
	int j = 0;
	for (; i < 3; i++)
	{
		for (; j < 3; j++)//j每次都没有初始化为0,而是保存为3
		{
			printf("12\n");
		}
	}

运行结果:
12
12
12
内层for循环中的j并没有初始化,在增加到3以后就一直保存为3,因此外层循环的i=1和2时不进入内层循环,故打印三次。

  1. 有两个循环变量
	int i = 0;
	int k = 0;
	for (i = k = 0; k = 0; i++, k++)//判断语句恒为假,一次也不执行
	{
		k++;
	}

运行结果:
在这里插入图片描述
是的,运行结果为空,其原因在于循环判断部分k=0为赋值运算而非==,k被赋值为0即假,因此不执行循环。

5.3 do while

特点:循环体至少执行一次

	int i = 1;
	do
	{
		if (i == 5)
			//break;
			continue;
		printf("%d ", i);
		i++;
	} while (i <= 10);

break运行结果:1 2 3 4
continue运行结果:
在这里插入图片描述
结果是个死循环,因为当i == 5时进入if内部执行continue,continue跳过了i++,直接转到while处进行判断,再次进入if’内部…

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值