【C】getchar函数与其在缓冲区的应用

简介: 【C】getchar函数与其在缓冲区的应用

💻前言

🍁介绍分析getchar函数以及其在缓冲区的应用

💻.1 getchar函数与缓冲区

首先我们知道是getchar是用来获取一个字符的,而对应的putchar函数可以用来打印一个字符

73d8c9be8b2a4960a39693770de0ac9a.png

getchar函数的返回值是用户输入字符所对应的ASCII码,若遇到文件结尾(End-Of-File)或者读取时遇到错误则返回EOF(-1),且将用户输入的字符回显到屏幕。

当使用getchar获取一个字符的时候,其实它不是从我们的键盘上直接获取的,在计算机的内存内存空间中存在一个 缓冲区。

1.缓冲区又称为缓存,它是内存空间的一部分。也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区。

2.缓冲区根据其对应的是输入设备还是输出设备,分为输入缓冲区和输出缓冲区。

看下面这段代码

#include<stdio.h>
int main()
{
  int ch = 0;
  while ((ch = getchar())!=EOF)
  {
    //printf("%c",ch);
    putchar(ch);//与printf打印一样的效果
  }
  return 0;
}

73d8c9be8b2a4960a39693770de0ac9a.png

看程序的执行过程,实质上当我们从键盘上输入一个字符时,这个字符是先存放在缓冲区当中等待getchar进行读取;

当我们在键盘上敲入回车后,getchar便会读取缓存区中的一个字符,而敲回车换行进行输出,实际上敲回车又在缓冲区放入了一个\n,在下一次循环getchar会将这个\n读走,所以输出一个字符后便自动换行了;

当输入^Z(Ctrl+z)时,getchar读取后会返回一个EOF,循环结束(VS编译器中可能需要按三次Ctrl+z,算是VS编译器的一点小问题,其他的编译环境正常一次即可)。

73d8c9be8b2a4960a39693770de0ac9a.png

getchar使用实例:只打印数字字符,跳过其他字符的,代码如下。

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

💻.2 getchar清理缓存区

看这样一个代码,输入一个密码,然后进行确认密码。

#include<stdio.h>
int main()
{
  int password[20] = { 0 };
  printf("请输入密码:>");
  scanf("%s", password);//假设密码是abcdef
  printf("请确认密码(Y/N):>");
  int ret = getchar();
  if (ret == 'Y')
  {
    printf("确认成功\n");
  }
  else
  {
    printf("确认失败\n");
  }
  return 0;
}

73d8c9be8b2a4960a39693770de0ac9a.png

看这里的运行结果,还没有输入Y/N进行确认,便已经输出了结果了

这里是因为我们在输入abcdef后,它只是在缓冲区等待进行读取,当我们在键盘上敲入回车后,在缓冲区放入了一个\n,scanf才会进行读取,要注意的是scanf在遇到空白符(如换行、空格等)会结束读取,所以scanf并不会去读取\n,getchar会将缓冲区中的\n读走进行判断结束了程序。

73d8c9be8b2a4960a39693770de0ac9a.png

这里在scanf读走字符串后我们需要解决掉这个\n 才可以正常进行确认密码,也就是需要清理缓冲区


如果只是要清理上面的问题,我们只需要把缓冲区的\n清理掉即可,做法如下:

#include<stdio.h>
int main()
{
  int password[20] = { 0 };
  printf("请输入密码:>");
  scanf("%s", password);
  getchar();//清理\n
  printf("请确认密码(Y/N):>");
  int ret = getchar();
  if (ret == 'Y')
  {
    printf("确认成功\n");
  }
  else
  {
    printf("确认失败\n");
  }
  return 0;
}

73d8c9be8b2a4960a39693770de0ac9a.png

这里在scanf后加了一个getchar,当scanf读取结束后,getchar接着就会把缓冲区的\n清理掉;但这个方法只是可以临时解决问题,存在很大的弊端,看下面这个运行结果

73d8c9be8b2a4960a39693770de0ac9a.png

当输入的密码中包含空格,因为scanf遇到空白符会结束读取;而这时scanf后的getchar只能清理一个字符,后面的qwer\n就无法被清理而导致无法正常进行密码的确认,所以说这种方法有时候无法完全清理缓冲区,原因是这里的getcher只能实现一次清理,而如果我们可以实现多次清理就可以解决这个弊端。

下面是优化后的清理缓存区的代码。

将scanf后的getchar换成

while ((ch = getchar()) != ‘\n’)

{

;

}

这条循环语句会让getchar逐个清理缓存区的字符,直到将最后的\n清理掉循环结束.

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

73d8c9be8b2a4960a39693770de0ac9a.png

💻结语

各位小伙伴,看到这里就是缘分嘛,希望我的这些内容可以给你带来那么一丝丝帮助,可以的话三连支持一下呗(关注✌️点赞✌️评论✌️)!!!
感谢每一位走到这里的小伙伴,我们可以一起学习交流,一起进步!!!加油!!!

864ac7b31466096ff78a66b1d305f2b.png

目录
相关文章
|
7月前
|
C语言
[字符串和内存函数]strcmp和strncmp以及memcmp的区别
[字符串和内存函数]strcmp和strncmp以及memcmp的区别
178 0
|
7月前
|
C语言
[字符串和内存函数]strcpy和strncpy的区别
[字符串和内存函数]strcpy和strncpy的区别
61 0
|
7月前
|
存储
文件的顺序读写——顺序读写函数——fgets、fgetc、fputs、 fputc
文件的顺序读写——顺序读写函数——fgets、fgetc、fputs、 fputc
113 0
|
7月前
|
存储
fread和fwirte函数
fread和fwirte函数
50 0
|
2月前
|
存储
底层文件操作的各种函数(二)------printf,fprintf,sprintf,scanf,fscanf,sscanf的对比以及文件缓冲区
底层文件操作的各种函数(二)------printf,fprintf,sprintf,scanf,fscanf,sscanf的对比以及文件缓冲区
57 2
|
6月前
|
C语言
用getchar和putchar读/写字符
用getchar和putchar读/写字符
66 0
|
6月前
fgets函数和fputs函数的使用
fgets函数和fputs函数的使用
|
6月前
|
C语言
C语言进阶——sprintf与sscanf、文件的随机读写(fseek、ftell、rewind)
C语言进阶——sprintf与sscanf、文件的随机读写(fseek、ftell、rewind)
55 0
|
7月前
|
PHP C++
[字符串和内存函数]strcpy和strlen字符串函数的详解和模拟
[字符串和内存函数]strcpy和strlen字符串函数的详解和模拟
74 0
|
存储 数据安全/隐私保护
scanf函数读取数据 & 清空缓冲区
scanf函数读取数据 & 清空缓冲区
407 0