【C语言航路外传】输入输出函数及输入缓冲区的那点事

简介: 【C语言航路外传】输入输出函数及输入缓冲区的那点事

一、getchar,putchar的使用

当我们想要在输入一个字符,并且打印它的时候,我们头脑中最先想到的一定是scanf和printf,这两个函数搭配使用来输出并且打印。

#include<stdio.h>
int main()
{
  char n;
  scanf("%c", &n);
  printf("%c", n);
  return 0;
}

这是最简单的一种方法了。

除此之外我们在来介绍两个函数,getchar和putchar

#include<stdio.h>
int main()
{
  char n;
  //scanf("%c", &n);
  //printf("%c", n);
  n = getchar();//从键盘中获取一个字符
  putchar(n);//输出一个字符到屏幕上
  return 0;
}

需要注意的是:scanf和printf可以针对各种各样的数据进行输入输出。但是getchar和putchar仅仅针对字符

二、getchar和scanf函数的返回值

1.getchar的返回值

我们来了解一下getchar这个函数,我们先进入一个网站,这个网站里面有着各种库函数的使用详解。c语言库函数,在这个库函数网站里面,我们在上面搜索getchar

搜索之后我们进入如下界面

在这里,我们会发现,int getchar (void),也就是说,getchar接收的参数是void,也就是空的意思,即不需要参数,然后返回一个int类型的整型数字,这个int的类型的整型数字就是从我们键盘上读取到的那个数字的ASCII值。它还是一个只获取一个字符类型的函数。但是如果获取失败,他就返回EOF,注意EOF就是-1。

2.scanf的返回值

对于scanf我们也同样了解一下。

成功时,函数返回成功填充的参数列表的项数。由于匹配失败、读取错误或到达文件末尾,此计数可以与预期的项数匹配,也可以更少(甚至为零)。

如果在读取过程中发生读取错误或到达文件末尾,则设置适当的指示符(feof或ferror)。并且,如果在成功读取任何数据之前发生任何一种情况,则返回EOF。

如果在解释宽字符时发生编码错误,该函数将errno设置为EILSEQ。

这是scanf的返回值,也就是说,scanf的返回值等于scanf成功读取到数据的个数。如果失败,则返回EOF,即-1。

举个例子,请看下面一段代码。

#include<stdio.h>
int main()
{
  int a, b,ret;
  ret = scanf("%d %d", &a, &b);
  printf("%d", ret);
  return 0;
}

这段代码中如果输入两个正常的数,那么将会读取成功。打印结果为2

如果只成功输入一个数字,注意在输入函数中输入crtl+z就会读取失败一个数。但是visual stdio环境下scanf有一个小bug,需要三次crtl+z才可以停止。其他编译器都是一次即可。如下图所示。

如果两个数据都没有读入,则返回EOF,注意EOF就是-1。它和-1一模一样,只不过多了一个写法罢了。因为我们的编译器中有一个预处理指令是

#define EOF -1

如果输入的字符则会输出0.

那么说了这么多,scanf的返回值有什么用呢?

其实,我们在牛客网刷题时候,有时候题目要求多组输入,这时候我们就需要它来搭配循环使用了

#include<stdio.h>
int main()
{
  int a, b;
  while (scanf("%d %d",&a,&b) != EOF)
  {
    //代码段;
  }
  return 0;
}
#include<stdio.h>
int main()
{
  int a, b;
  while (scanf("%d %d",&a,&b) == 2)
  {
    //代码段;
  }
  return 0;
}

以上这两种方法都可以使用,要么等于2,要么不等于EOF。来达到多组输入的目的。但是这两者还是有一点区别,像上面的代码中,要有两个数据多组输入的话,我只输入成功一个数据,一个输入失败。如果是前者的话,那就不会进入循环,直接停止多组输入,如果是后者,则继续进入多组输入,具体选择哪一种需要看具体的需求。

三、输入缓冲区

我们看这样一段代码

#include<stdio.h>
int main()
{
  int a;
  while (scanf("%d", &a) == 1)
  {
    printf("%d ", a);
  }
  return 0;
}

这段代码我们运行一下,观察一下它的输入时候的过程

然后我们继续看下面这段代码

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

运行一下,观察输入的过程。

不知道大家看出输入有一点小区别了吗。

我们会发现,第二段代码中似乎莫名奇妙多输出了一个换行。为什么会多出一个换行呢,而scanf里面没有呢?

我们首先需要了解一下缓冲区的概念。

无论是我们的scanf还是getchar它都不会直接从我们的键盘上读取一个数据,而是先从键盘上输入到缓冲区,然后这两个函数再从缓冲区里拿数据。我们画一个图可以更加形象的演示这个过程

因为我们在输入的时候会输出一个a 和一个\n所以输入缓冲区内会有两个数据

在第二段代码中,我们的getchar会首先获取一个a,然后putchar会将其输出。 不过这之后,我们输入缓冲区还有一个\n,这个仍然会被ch获取,然后输出这个\n,也就是换行。

那到这里有人就肯定有疑问,为什么scanf不会有这个现象呢,其实scanf他是不会读入这个\n还有空格这些特殊的字符的。所以scanf在输入的时候不会出现自动换行的效果。而我们的getchar是可以读入\n还有空格的,因为getchar是获取字符的,\n和空格恰巧就是一个字符,所以可以读入。产生一些意想不到的效果。这是一个很细节的事情。很多人都会在这里犯一些经典的错误标准的零分。

比如下面就举一个经典的错误标准的零分

#include<stdio.h>
int main()
{
  char password[20] = { 0 };
  int ch = 0;
  printf("请输入密码");
  //数组名本身就是地址,所以不需要&
  scanf("%s", password);
  printf("请确认密码(Y/N):>");
  ch = getchar();
  if (ch == 'Y')
  {
    printf("确认成功");
  }
  else
  {
    printf("确认失败");
  }
  return 0;
}

这段代码运行结果为

直接提示错误。这说明有问题。问题出在哪呢,就是我们的输入缓冲区,下图是我们的运行过程图,我们将123456放进scanf中,然后缓冲区还有一个\n,我们的\n就将其放入了getchar中,这样我们的ch中就是一个换行字符,所以会出现确认失败了。

那么如何规避这种错误呢。我们可以在scanf结束后再次getchar一下来消除掉这个\n,但是这个不一定是一个好方法,因为如果我们缓冲区的字符不止一个,就处理不了了

如图所示,因为我们的scanf只拿走空格之前的或者换行之前的。所以此时缓冲区还剩下了,很多其他的字符,最后还剩一个\n。在这里谈起最后一个字符是\n。想必你也已经想到解决方法了

没错,就是使用一个循环,判断条件就是,getchar()!='\n'。里面的循环体,是一个空的,这样我们就可以清除输入缓冲区了。代码实现如下

#include<stdio.h>
int main()
{
  char password[20] = { 0 };
  int ch = 0;
  printf("请输入密码");
  //数组名本身就是地址,所以不需要&
  scanf("%s", password);
  while (getchar()!='\n')
  {
    ;
  }
  printf("请确认密码(Y/N):>");
  ch = getchar();
  if (ch == 'Y')
  {
    printf("确认成功");
  }
  else
  {
    printf("确认失败");
  }
  return 0;
}

我们最后再来看一段代码

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

提示:continue在while循环中的意思是:

continue是用于终止本次循环的,也就是本次循环中continue后面的代码都不会被再次执行

而是直接跳转到while语句的判断部分,进行下一次的循环入口判断。

运行结果为,只能打印,0--9之间的字符,其余全部不打印,因为即便是\n出现了输入缓冲区的作用也会因为满足判断条件,而被终止不会被打印出来


总结

好了,本次外传就讲解这么多,主要就是这个输入缓冲区的作用,以及scanf和getchar 的返回值,以及EOF的返回值,如果本文章对你有帮助,不要忘记点赞加收藏哦。

相关文章
|
1天前
|
C语言
【海贼王编程冒险 - C语言海上篇】库函数怎样模拟实现?
【海贼王编程冒险 - C语言海上篇】库函数怎样模拟实现?
5 1
|
1天前
|
搜索推荐 C语言
c语言qsort函数的模拟实现
c语言qsort函数的模拟实现
7 1
|
2天前
|
C语言
【C语言】:浅谈函数 fscanf/sscanf 和 fprintf/sprintf
【C语言】:浅谈函数 fscanf/sscanf 和 fprintf/sprintf
9 1
|
1天前
|
C语言
【C语言基础篇】字符串处理函数(四)strcmp的介绍及模拟实现
【C语言基础篇】字符串处理函数(四)strcmp的介绍及模拟实现
|
1天前
|
存储 C语言
【C语言基础篇】字符串处理函数(三)strcat的介绍及模拟实现
【C语言基础篇】字符串处理函数(三)strcat的介绍及模拟实现
|
1天前
|
C语言
【C语言基础篇】字符串处理函数(二)strcpy的介绍及模拟实现
【C语言基础篇】字符串处理函数(二)strcpy的介绍及模拟实现
|
1天前
|
C语言
【C语言基础篇】字符串处理函数(一)strlen的介绍及模拟实现
【C语言基础篇】字符串处理函数(一)strlen的介绍及模拟实现
|
1天前
|
存储 缓存 移动开发
【C语言基础篇】scanf()函数详解
【C语言基础篇】scanf()函数详解
|
1天前
|
C语言 C++
C语言printf()函数详解
C语言printf()函数详解
|
1天前
|
编译器 C语言 C++
初识c语言函数
初识c语言函数
7 0