04-循环语句(while 循环)

一、while 循环的语法结构

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

【描述】表达式结果为真(非0),就执行循环语句否则循环语句不执行

【注】循环语句可能不止一条,可能是一个代码块!!!

二、举例演示

1、示例

【例子】在屏幕上打印 1~10 的数字。

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

int main()
{
	int i = 1;

	while (i <= 10)
	{
		printf("%d ", i);
		i++;
	}

	return 0;
}

 2、示例调试

(1)i = 1

i = 1,满足 i < 10 的条件,进入 while 的循环主体,执行 printf 函数和 i++ 语句,跳出循环时 i = 2

(2)i = 2

i = 2,满足 i < 10 的条件,进入 while 的循环主体,执行 printf 函数和 i++ 语句,此时 i = 3

(3)i = 3

i = 3,满足 i < 10 的条件,进入 while 的循环主体,执行 printf 函数和 i++ 语句,此时 i = 4

(4)i = 4

i = 4,满足 i < 10 的条件,进入 while 的循环主体,执行 printf 函数和 i++ 语句,此时 i = 5

(5)i = 5

i = 5,满足 i < 10 的条件,进入 while 的循环主体,执行 printf 函数和 i++ 语句,此时 i = 6

(6)i = 6

i = 6,满足 i < 10 的条件,进入 while 的循环主体,执行 printf 函数和 i++ 语句,此时 i = 7

(7)i = 7

i = 7,满足 i < 10 的条件,进入 while 的循环主体,执行 printf 函数和 i++ 语句,此时 i = 8

(8)i = 8

i = 8,满足 i < 10 的条件,进入 while 的循环主体,执行 printf 函数和 i++ 语句,此时 i = 9

(9)i = 9

i = 9,满足 i < 10 的条件,进入 while 的循环主体,执行 printf 函数和 i++ 语句,此时 i = 10

(10)i = 10

i = 10,满足 i = 10 的条件,进入 while 的循环主体,执行 printf 函数和 i++ 语句,此时 i = 11

(11)i = 11

i = 11,不满足 i <= 10 的条件,跳出 while 的循环主体,结束程序!!!

三、while 语句执行流程

四、while 循环中的 break

在 while 循环中,break 的作用是用于永久的终止循环。

1、示例

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

int main()
{
	int i = 1;

	while (i <= 10)
	{
		if (i == 5)
			break;

		printf("%d ", i);
		i++;
	}

	return 0;
}

2、示例调试

(1)i = 1

i = 1,满足 i < 10 的条件,进入 while 的循环主体,首先判断 i != 5,跳过 break 语句,然后执行 printf 函数和 i++ 语句,跳出循环时 i = 2

(2)i = 2

i = 2,满足 i < 10 的条件,进入 while 的循环主体,首先判断 i != 5,跳过 break 语句,然后执行 printf 函数和 i++ 语句,跳出循环时 i = 3

(3)i = 3

i = 3,满足 i < 10 的条件,进入 while 的循环主体,首先判断 i != 5,跳过 break 语句,然后执行 printf 函数和 i++ 语句,跳出循环时 i = 4

(4)i = 4

i = 4,满足 i < 10 的条件,进入 while 的循环主体,首先判断 i != 5,跳过 break 语句,然后执行 printf 函数和 i++ 语句,跳出循环时 i = 5

(5)i = 5

i = 5,满足 i < 10 的条件,进入 while 的循环主体,首先判断 i == 5,执行 break 语句,然后直接跳到 return 0 最终结束程序

 五、while 循环中的 continue

在 while 循环中,continue 的作用是跳过本次循环中 continue 后面的代码,直接去 while 循环的判断部分,看是否要再进行下一次的循环。

1、示例

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

int main()
{
	int i = 1;

	while (i <= 10)
	{
		if (i == 5)
			continue;

		printf("%d ", i);
		i++;
	}

	return 0;
}

【注】输出的光标一直闪烁,说明代码还在运行,只不过陷入了死循环!!!

2、示例调试

(1)i = 1

i = 1,满足 i < 10 的条件,进入 while 的循环主体,首先判断 i != 5,跳过 continue 语句,然后执行 printf 函数和 i++ 语句,跳出循环时 i = 2

(2)i = 2

i = 2,满足 i < 10 的条件,进入 while 的循环主体,首先判断 i != 5,跳过 continue 语句,然后执行 printf 函数和 i++ 语句,跳出循环时 i = 3

(3)i = 3

i = 3,满足 i < 10 的条件,进入 while 的循环主体,首先判断 i != 5,跳过 continue 语句,然后执行 printf 函数和 i++ 语句,跳出循环时 i = 4

(4)i = 4

i = 4,满足 i < 10 的条件,进入 while 的循环主体,首先判断 i != 5,跳过 continue 语句,然后执行 printf 函数和 i++ 语句,跳出循环时 i = 5

(5)i = 5

i = 5,满足 i < 10 的条件,进入 while 的循环主体,首先判断 i == 5,执行 continue 语句,然后没有执行 continue 后面的任何一条语句而是跳回了 while 的条件判断,而此时的 i 依旧还是 5 ,进入 i == 5 的判断,再一次的执行 continue 语句,然后又跳回了 while 的条件判断。

【注】代码一直在 continue 语句和 while 的条件判断处来回的跳,就这样陷入了死循环(输出的光标一直闪烁,说明代码还在运行,只不过陷入了死循环)!!!

六、示例

/*
 * getchar:获取字符
 * 函数返回类型:int
 * 函数名:getchar
 * 入口参数:void(无)
 * 函数含义:从一个 stream 中读取一个字符,或者从 stdin(标准输入,即键盘)中获取一个字符
 * 函数返回值:返回的是读取到的字符。在读取的时候遇到读取错误或者文件结束,函数返回的是 EOF
 * EOF:end of file(文件结束标志)
 * 在库中EOF定义:#define EOF    (-1),即 EOF 的本质是 -1
 */
int getchar(void);

/*
 * putchar:输出字符
 * 函数返回类型:int
 * 函数名:putchar
 * 入口参数:int c(整型变量)
 * 含义:输出一个字符
 */
int putchar(int c);

【功能】输入什么字符,就输出什么字符。

【注】当在键盘中按下 Ctrl + Z 就能跳出 getchar 的读取!!!

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

int main()
{
	int ch = 0;

	while ((ch = getchar()) != EOF)
		putchar(ch);

	return 0;
}

【注】EOF 的取值是 -1(-1 不是 ASCII 码值,因此 getchar 的返回类型是整型)!!!

1、getchar 的读取原则

(1)等待

在 getchar 和 键盘中间有一个缓冲区。首先 getchar 看 缓冲区 是空的就开始等待。

【原因】缓冲区是空的。

(2)读取字符

键盘输入 S\n 之后,getchar 首先读取一个 SS放入 ch 中,然后再在屏幕打印一个 S 。之后,又回到 while 的判断条件处再一次的执行 getchar ,这一次读取\n(换行),就放入 ch 中,然后再在屏幕打印一个 \n(换行)。故再次输入一个字符就会在下一行中呈现出来。

【注】getchar 是读取字符的,是不会忽略 \n(回车)的。因为 getchar 认为缓冲区中的任何字符都是字符!!!

2、示例分析

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

int main()
{
	int ch = 0;

	while ((ch = getchar()) != EOF)
		putchar(ch);

	return 0;
}

① 定义整型变量 ch。

② getchar 读取一个字符,并放入 ch 中。

③ 判断 ch 不等于 EOF 就说明 getchar 读取的是正常的字符。

④ 进入 while 的循环主体。

⑤ 执行 putchar 给 ch 中的字符打印出来。

⑥ 如果 getchar 返回的字符放入的 ch 并且发现返回的这个字符是 EOF ,而 EOF == EOF ,此时 while 的判断条件为假,因此不再进入 while 的主体循环去执行 getchar 函数。

七、举例1

【实现功能】输入密码,并确认密码是否正确。

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

int main()
{
	char password[20] = { 0 };
	printf("请输入密码:>");

	/* password 是数组,数组的数组名本来就是地址 */
	scanf("%s", password);

	printf("请确认密码(Y/N):>");

	int ch = getchar();
	if (ch == 'Y')
	{
		printf("密码确认成功!\n");
	}
	else
	{
		printf("密码确认失败!\n");
	}

	return 0;
}

【注】还没有进行确认输入就被判断失败了。故,上述举例失败!!!

 (1)输入函数

getchar();

scanf();

对于 getchar scanf 这些输入函数来说,不是直接从键盘上获取数据,而是从缓冲区中获取数据。当调用这些输入函数时,这些输入函数会去缓冲区看是否有数据,如果没有数据,就会去等待,一直等待到键盘输入数据到缓冲区里。这些输入函数若发现缓冲区里有数据了,就会将这些数据取走。

(2)例子解析(分析错误原因)

① 首先是 printf 函数请输入密码;

② 其次是第一次调用 scanf 函数,scanf 前往缓冲区里查看数据;

③ 然后从键盘中输入一系列的字符串(123456\n)放入缓冲区里(其中 \n ,即回车,会触发 scanf读取内容);

④ scanf 将缓冲区中的 123456 取走,并放入 password 这个数组里面;

⑤ 紧接着就会在执行下面的 printf 函数输出 “请确认密码(Y/N):>” ;

⑥ 按道理来说会在往后执行 getchar 函数等待获取是 Y 还是 N

【注】实际并没有等待获取 Y 或是 N !!!

⑦ 此时缓冲区里还有一个 \n 并没有被上一次的 scanf 给取走,这时候 getchar 将这个缓冲区剩余\n 取走,并将这个 \n 存放进了变量 ch 里面了,没有多做等待。

⑧ 这时候 ch \n ,又不等于 Y ,就直接执行 else 中的 printf 函数,然后就输出了 “密码确认失败!”

【故】没有执行获取 Y 或者 N 的语句。

(3)例子更正1

【更正点】将缓冲区中的 \n 清除(在调用 getchar 函数之前)。

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

int main()
{
	char password[20] = { 0 };
	printf("请输入密码:>");

	/* password 是数组,数组的数组名本来就是地址 */
	scanf("%s", password);

	printf("请确认密码(Y/N):>");

	/* 清理缓冲区 */
	getchar();	//处理 \n

	int ch = getchar();
	if (ch == 'Y')
	{
		printf("密码确认成功!\n");
	}
	else
	{
		printf("密码确认失败!\n");
	}

	return 0;
}

【注】当输入 "123456 abc" 时就会再一次失败!!!

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

int main()
{
	char password[20] = { 0 };
	printf("请输入密码:>");

	/* password 是数组,数组的数组名本来就是地址 */
	scanf("%s", password);

	printf("请确认密码(Y/N):>");

	/* 清理缓冲区 */
	getchar();	//处理 \n

	int ch = getchar();
	if (ch == 'Y')
	{
		printf("密码确认成功!\n");
	}
	else
	{
		printf("密码确认失败!\n");
	}

	return 0;
}

(4)例子更正1失败分析

① 首先是 printf 函数请输入密码;

② 其次是第一次调用 scanf 函数,scanf 前往缓冲区里查看数据;

③ 然后从键盘中输入一系列的字符串(123456 abc\n)放入缓冲区里;

④ scanf 将缓冲区中的 123456 取走(取走空格前面数据),并放入 password 这个数组里面;

⑤ 此时缓冲区里的数据还有很多( abc\n,,空格abc回车);

⑥ 然后在执行 getchar 函数,此函数仅仅取走了一个字符(空格),这时候缓冲区里仍然有很多数据(abc\n,即,abc回车)。

⑤ 紧接着就会在执行下面的 printf 函数输出 “请确认密码(Y/N):>” ;

⑥ 按道理来说会在往后执行 getchar 函数等待获取是 Y 还是 N

【注】实际并没有等待获取 Y 或是 N !!!

⑦ 此时缓冲区里还有一个 abc\n 并没有被上一次的 getchar 给取走,这时候又一次执行 getchar 将这个缓冲区剩余abc\n 中的一个字符(a)取走,并将这个 a 存放进了变量 ch 里面了,没有多做等待。

⑧ 这时候 ch a ,又不等于 Y ,就直接执行 else 中的 printf 函数,然后就输出了 “密码确认失败!”

【故】没有执行获取 Y 或者 N 的语句。

(5)例子更正2

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

int main()
{
	char password[20] = { 0 };
	printf("请输入密码:>");

	/* password 是数组,数组的数组名本来就是地址 */
	scanf("%s", password);

	printf("请确认密码(Y/N):>");

	/* ---------- 清理缓冲区 ---------- */
	int tmp = 0;	//定义一个整型变量 tmp

	/* getchar 读取的字符不是 \n,就执行下面的空语句 *
	 * 使用 while 循环直到将缓冲区里的数据全部清除干净
	 * 作用:清除缓冲区中的多个字符
	 */
	while ((tmp = getchar()) != '\n')
	{
		;
	}
	/* ---------- 清理缓冲区 ---------- */

	int ch = getchar();
	if (ch == 'Y')
	{
		printf("密码确认成功!\n");
	}
	else
	{
		printf("密码确认失败!\n");
	}

	return 0;
}

 八、举例2

ASCII 码字符(0)的十进制是 48,字符(9)的十进制是 57,即字符(0 ~ 9)十进制就是 48 ~ 57。详见:ASCII码

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

int main()
{
	int ch = 0;

	while ((ch = getchar()) != EOF)
	{
		/* 如果不是数字字符就执行 continue 语句 */
		if (ch < '0' || ch > '9')
			continue;

		putchar(ch);	//只打印数字字符
	}

	return 0;
}

【注】此示例子仅仅打印数字字符!!!

 九、总结

对于【例子】在屏幕上打印 1~10 的数字。

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

int main()
{
	int i = 1;                   //初始化

	while (i <= 10)              //判断部分
	{
		printf("%d ", i);
		i++;                     //调整部分
	}

	return 0;
}

循环语句中包含初始化、判断部分、调整部分对于 while 循环来说,随着循环语句的增加,这三个部分的距离也就会越来越远。一旦要进行修正,就会给编程增加很大的负担。

【注】循环语句中初始化、判断部分、调整部分任意一个发生改变都会影响到循环的结果!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值