C语言分支与循环(4)--- while语句的补充与缓冲区讲解
  uUWKQE7Avyk4 2023年11月02日 87 0

我们接着上篇文章中的代码,继续对代码进行分析

#include<stdio.h>
int main(void)
{
int ch = 0;
while((ch = getchar()) != EOF){
putchar(ch);
}
return 0;
}

我们也直到了,这个程序创建了一个int型的变量ch,并赋值0,随后创建while语句,while语句中的表达式将getchar()函数得到的字符传给ch,并和EOF(全称End Of File)进行比较,若字符不等于EOF。则调用putchar()函数将用户输入的内容进行输出,若想要停止程序则需要同时按下Ctrl+Z(Ctrl+C也可以但是不推荐,容易导致程序异常)进行结束,关于EOF可以右击EOF,然后点击转到定义,查看其定义,如图所示:

C语言分支与循环(4)--- while语句的补充与缓冲区讲解_getchar

C语言分支与循环(4)--- while语句的补充与缓冲区讲解_EOF_02

我们可以看到EOF的值在头文件stdio.h中被定义成了-1,接下来我们再来看一段代码:

#include<stdio.h>
int main(void)
{
char password[18] = {0};
int input;
printf("请输入密码:");
scanf("%s",password);
printf("请确认是否输入正确(Y/N):");
getchar();
if(getchar == 'Y'){
printf("确认成功!");
}else{
printf("确认失败!");
}
return 0;
}

程序看似没有任何问题,也能正常编译运行,但是当我们输入密码并确认的时候问题出现了,当我们输入密码后按下回车键的瞬间,程序被没有询问是否确认,而是直接执行了else语句,这是为什么呢?

让我们打开监视窗口进行观察:

C语言分支与循环(4)--- while语句的补充与缓冲区讲解_putchar_03

C语言分支与循环(4)--- while语句的补充与缓冲区讲解_while_04

我们可以发现当我们输入密码以后password字符串数组确实存放了我们输入的数据,但是与此同时input这个变量也变成了10,但是我们还没有进行输入,为什么input变量已经存放了一个10呢?

这时候我们可以编译并运行以下代码:

#include<stdio.h>
int main(void)
{
printf("%d",'\n');
return 0;
}

我们可以看到程序输出了10,也就是说\n这个转义字符的ASCII码值等于10,和上方input的值一模一样!原因就出在 printf("请输入密码"); 这行代码上面,当我们输入一串字符串以后,我们需要按下回车,这时候光标就会跳转到下一行,也就是说回车键导致的换行等于了\n的转义序列,并被保存了下来被getchar()进行了读取,所以input的值才会变成10,而我们判断的是input的值是否等于字符 Y ,很显然10不等于Y的ASCII码值89,所以会执行else语句,当我们将input的值在执行if语句前强制改成89的时候则会出现确认成功,如图所示:

C语言分支与循环(4)--- while语句的补充与缓冲区讲解_while_05

但是这都不是我们想要的结果,我们想要的是用户输入密码后,再输入Y/N进行确认

我们先来看一下输入函数的原理:

程序中出现的输入函数有 scanf() 与 getchar() 

当输入函数需要读取数据的时候会首先检测输入缓冲区,输入缓冲区中可能存放了一些数据,让输入缓冲区没有内容的时候,scanf()函数会要求用户输入数据,当用户输入数据以后scanf()函数会获取相应的数据,getchar()也与其相同,当getchar()函数读取数据的时候,首先也是检测输入缓冲区,若输入缓冲区有数据则读取输入缓冲区的数据,若没有则等待用户进行输入,如图所示:

C语言分支与循环(4)--- while语句的补充与缓冲区讲解_输入缓冲区_06

scanf()函数只会读取前面的123456,但不会将\n读取,所以导致输入缓冲区剩下了一个\n

getchar()函数发现输入缓冲区有东西,便不再要求用户进行输入,而是直接进行了读取

当我们知道了原因后,就可以着手想解决方案了,既然输入缓冲区中剩余一个 \n 那我再调用一次getchar()函数将其拿走不就可以了吗,如以下代码:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main(void)
{
	char password[18] = { 0 };
	int input;
	printf("请输入密码:");
	scanf("%s", password);
	printf("请确认是否输入正确(Y/N):");
	getchar();
	input = getchar();
	if (input == 'Y'){
		printf("确认成功!");
	}
	else{
		printf("确认失败!");
	}
	return 0;
}

我们在需要输入Y/N进行判断的语句前面再加上一个getchar()函数问题就解决了,如图所示:

C语言分支与循环(4)--- while语句的补充与缓冲区讲解_while_07

那这时候我们在密码处输入 123456 (空格) ABCD,则会发现程序又出现了刚刚的问题,如图所示:

C语言分支与循环(4)--- while语句的补充与缓冲区讲解_输入缓冲区_08

出错的原因是scanf()读取只会读取到空格前面的内容,空格后面的内容将不再被读取,以下是缓冲区中数据的简图:

C语言分支与循环(4)--- while语句的补充与缓冲区讲解_getchar_09

为了严谨性,我专门创建了一个变量i用于读取第一个getchar()所读取到的内容,结果如图所示:

C语言分支与循环(4)--- while语句的补充与缓冲区讲解_输入缓冲区_10

由此可见第一个getchar()所读取到的数据是32,而在ASCII表中32这个值对应的正是空格,如图所示:

C语言分支与循环(4)--- while语句的补充与缓冲区讲解_EOF_11

我们接着按F10进行调试,可以注意到input这个变量也从内存随机值变成了65,同样我们查询ASCII表可以发现65这个值对应的就是大写字母A,如图所示:

C语言分支与循环(4)--- while语句的补充与缓冲区讲解_getchar_12

所以让getchar()不读取 \n 的最好方法就是创建一个循环,利用循环语句,循环检测缓冲区中是否有 \n 存在,若有 \n 则一直读取,直到将 \n 读完位置,利用代码实现可以创建一个while循环语句:

int ch = 0;
while((ch = getchar()) != '\n'){
;
}

运用到程序中,则程序代码应就修改成:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main(void)
{
	char password[18] = { 0 };
	int input;
	int ch = 0;
	printf("请输入密码:");
	scanf("%s", password);
	printf("请确认是否输入正确(Y/N):");
	while ((ch = getchar()) != '\n')
	{
		;
	}
	input = getchar();
	if (input == 'Y'){
		printf("确认成功!");
	}
	else{
		printf("确认失败!");
	}
	return 0;
}

该程序创建了一个while循环语句用于循环读取缓冲区中的 '\n' ,直到缓冲区中没有 '\n' 跳出循环,且while循环中的语句为空语句,也就是不要执行任何代码,这时候我们再执行代码则可以正常的进行判断,如图所示:

C语言分支与循环(4)--- while语句的补充与缓冲区讲解_输入缓冲区_13

题目:编写一段代码,仅当用户输入0-9数字的时候才进行输出,其他输入一律不进行输出


#include<stdio.h>
int main(void)
{
int ch = 0;
while((ch = getchar()) != EOF)
{
if(ch < '0' || ch > '9'){
continue;
}else
putchar(ch);
}
return 0;
}

当if语句检测到0-9之外的字符则会执行continue语句,我们直到continue语句是结束本次循环,会导致continue语句后面的语句都不被执行,所以只有当输入0-9的数字时候才能进行输出,如1,2,30,60这些都是可以输出的

至此while循环大致讲解完成,缓冲区内容也进行了初识

                                                                                                2023/7/21

                                                                                                 王起舟

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

uUWKQE7Avyk4