您的位置:首页 > 编程语言 > C语言/C++

【C语言】最通俗易懂地讲解scanf、gets和getchar的区别(相信我,看了一定懂!!!)

2020-03-02 04:54 2166 查看

欢迎关注WX公众号:【程序员管小亮】

专栏C++学习笔记

声明

1)本文仅供学术交流,非商用。所以部分参考资料并没有详细对应。如果某部分不小心侵犯了大家的利益,还望海涵,并联系博主删除。
2)博主才疏学浅,文中如有不当之处,请各位指出,共同进步,谢谢。
3)此属于第一版本,若有错误,还需继续修正与增删。还望大家多多指点。大家都共享一点点,一起为祖国科研的推进添砖加瓦。

文章目录

  • 二、字符串
  • 三、总结
  • 参考文章
  • 〇、写在前面


    最近认真钻研了一下,

    scanf
    gets
    getchar
    的区别,发现好多写的博客都很凌乱,看了半天不知所云为何物,决定自己写一个博客记录总结一下。

    一、字符

    1、scanf(%c)

    首先要说的是

    scanf
    ,它是格式输入函数,标准格式如下:

    int scanf(const char * restrict format,...);

    标准输入流(stdin)
    中按照说明的格式读入多个字符,并存入 以输入参数的值为地址的变量 中,所以必须得有
    &
    ,除了把字符串读入字符数组中。

    为啥?

    很简单,因为数组变量名称本身就是特殊的指针,即,数组首元素的地址,故无需使用

    &
    取地址,完事。

    举个例子:

    char a[10];
    scanf("%s",a);


    没有

    &
    地址符,程序正常运行。

    scanf
    在遇到
    空格符
    回车符(\n)
    制表符(\t)
    时,都会认为本次输入结束,所有它不能接收
    空格符
    还有
    回车符(\n)
    ,那么它是如何处理
    回车符(\n)
    的呢?

    除了一种特殊情况:

    scanf()
    会忽略行开头的所有
    空格
    !!!

    scanf
    末尾回车符 的处理是把
    回车符(\n)
    保留在缓存中。

    #include<stdio.h>
    int main(){
    char a,ch;
    int count=0;
    while(1){
    scanf("%c",&a);
    count++;
    printf("**************\n");
    printf("%d\n",count);
    }
    
    return 0;
    }


    首先输入

    a
    ,然后
    回车
    ,因为
    scanf
    末尾回车符 的处理是把
    回车符(\n)
    保留在缓存中,所以除了
    a
    之外,还有
    回车
    也被读进来了,即,每次蹦两个数字。

    这一点和

    gets
    是不同的!!!在后面的
    gets
    中会有详细地介绍。

    小结

    不接收

    空格
    ,不接收
    回车

    2、getchar

    接着要说的,是

    getchar()
    函数。

    它的作用是从键盘获取且只能获取一个字符。

    定义如下:

    int getchar(void)

    getchar()
    函数是可以接收
    空格
    的,但是不能接收
    回车
    。即最后的
    回车符
    也不会被接收,
    getchar()
    是会舍弃最后的
    回车符
    的。

    回车
    是干啥用的呢?

    因为

    getchar
    函数只能输入字符型,所以在输入时遇到
    回车键(\n)
    才从缓冲区依次提取字符,遇到
    空格符
    不会结束,而是会接收它!!!

    下面来看一个例子:

    #include<stdio.h>
    int main(){
    char a,ch;
    int count=0;
    while((ch=getchar())!='q'){
    count++;
    printf("**************\n");
    printf("%d\n",count);
    }
    
    return 0;
    }


    首先确定的一件事是,

    getchar
    是不接收
    回车
    的,所以正常情况下的计数应该是1。

    也同样是因为它本身只能接收1个字符,所以这个

    回车
    被留在缓存流中了,而我们这里的程序是遇到
    q
    才停止,故而程序又循环了一下,相当于输入了一个
    回车
    !!!

    如果稍微修改一下程序为:

    #include<stdio.h>
    int main(){
    char a,ch;
    int count=0;
    while((ch=getchar())!='\n'){
    count++;
    printf("**************\n");
    printf("%d\n",count);
    }
    
    return 0;
    }


    可以看到程序只运行了一次就停止了,因为

    回车
    是留在缓存流中的,默认输入了。

    小结

    接收

    空格
    ,不接收
    回车

    3、实例

    总结一下两个函数的使用:

    输入完成后:

    • scanf
      把数据一把全梭了;
    • getchar
      把数据一个一个从兜里掏。

    在很多时候会出现这样一种情况,即先输入了一个

    scanf
    的语句,然后可能要用到
    gets
    ,这个时候上一个
    scanf
    留下的
    回车
    就会打搅乱下面的数据读取!!!这个时候就需要加一个
    回车符(\n)
    ,用
    scanf('\n);
    ;或者读取这个
    回车符(\n)
    ,用
    gets();
    getchar();

    比如最近在做PTA上的C语言题库时发现的一个题:

    给定

    n
    本书的名称和定价,本题要求编写程序,查找并输出其中定价最高和最低的书的名称和定价。

    #include<stdio.h>
    struct book{
    char name[31];
    double price;
    };
    int main(){
    struct book a[10];
    int i;
    double max=-1,min=10000;
    int flag1=0,flag2=0;
    int n;
    scanf("%d",&n);
    for(i=0;i<n;++i){
    scanf("\n");	// 去除回车
    //gets();
    //getchar();
    gets(a[i].name);
    scanf("%lf",&a[i].price);
    if(max<a[i].price){
    max=a[i].price;
    flag1=i;
    }
    if(min>a[i].price){
    min=a[i].price;
    flag2=i;
    }
    }
    printf("%.2lf, %s\n",a[flag1].price,a[flag1].name);
    printf("%.2lf, %s\n",a[flag2].price,a[flag2].name);
    
    return 0;
    }


    首先使用

    scanf
    输入的书的数量3,留下了一个
    回车
    ,如果在这里直接接着使用一个
    scanf
    的话,就会出错:

    因为
    回车
    会留在缓存流中,并被下一个函数
    get
    读取到,从而扰乱了本来的数据读取,继而出现了非预期结果。

    小结

    一定要注意

    scanf
    回车符
    !!!

    二、字符串

    1、scanf(%s)

    %c
    %s
    的区别是一个是字符,一个是字符串,从这里可以看得出,
    scanf
    函数能对各种类型进行输入,

    而不仅仅局限于字符或是字符串,而字符是
    getchar
    ,字符串是
    gets

    不过,无论是对待字符还是字符串,

    scanf
    的处理都是比较相似的,这一点倒是比较容易学习和使用,但是 来自
    pudn
    ,只有一段开头话

    • 中文版本:在数据大量的情况下,用

      gets
      读取快于
      scanf()
      10倍以上。

    • 英文版本:A large number of cases in the data, using

      gets
      read faster than
      scanf
      10 times.

    小结

    不接收

    空格
    回车

    2、gets

    到这里,你应该不会忘记上面说过的

    scanf
    是如何处理
    回车符(\n)
    的了,这一点和
    gets
    是差别巨大的!!!

    gets
    对末尾
    回车符
    的处理方式是,接收
    回车
    ,但把
    回车
    替换为
    \0
    ,不像
    scanf
    是留在缓存中,所以在用
    gets
    时,要注意数组的大小增加1,不然就会出现数组越界等问题。

    还是看个例子,还是上面那个题,虽然题中说的是不超过30个字符,但是因为还有一个
    回车符
    转换成的
    空字符
    ,所以数组大小需要加1!!!


    除了

    回车
    就是
    空格
    的问题了,
    gets
    是接收
    空格
    的,也就是可以读取并输出
    空格


    终止的标志是
    Enter
    结束输入(空格不结束),比如这里的
    Hello
    World
    之间的空格就是正常的。

    #include<stdio.h>
    #include<string.h>
    int main(){
    char a[100];
    gets(a);
    int i;
    for(i=0;i<strlen(a);i++){
    printf("%c",a[i]);
    }
    
    return 0;
    }

    如果换成

    scanf
    的话,就只能读取一半了,因为空格也是它的终止符!

    #include<stdio.h>
    #include<string.h>
    int main(){
    char a[100];
    int i;
    scanf("%s",&a);
    for(i=0;i<strlen(a);i++){
    printf("%c",a[i]);
    }
    
    return 0;
    }


    小结

    接收

    空格
    回车

    3、实例

    最直接的方式进行对比就是求一下字符串的长度。

    #include<stdio.h>
    #include<string.h>
    int main(){
    char a[100];
    gets(a);
    printf("%d",strlen(a));
    
    return 0;
    }

    #include<stdio.h>
    #include<string.h>
    int main(){
    char a[100];
    //    gets(a);
    scanf("%s",&a);
    printf("%d",strlen(a));
    
    return 0;
    }

    这也就解释了为什么前面要用

    gets
    或者是
    getchar
    去去除
    回车

    三、总结

    • scanf
      忽略行开头的所有空格,并以各种格式化进行数据输入,直到遇到
      空格
      回车
      结束输入,不接收
      空格
      回车
      ,留在缓存区中;
    • getchar
      只读取一个字符,包括
      空格
      但是不包括
      回车
      回车
      会留在缓冲区中;
    • gets
      读取以任何字符开头的字符串,读取的字符串包括
      空格
      但是不包括
      回车
      ,以
      回车
      结束输入,接收
      空格
      回车
      ,但之后会丢弃
      回车
      并以
      \0
      代替;

    最后的一个图给出常用的

    while
    表达形式:


    参考文章

    • https://zhidao.baidu.com/question/63301588.html
    • https://www.php.cn/faq/415503.html
    • https://www.runoob.com/cprogramming/c-tutorial.html
    • https://www.cnblogs.com/hlongch/p/5742477.html
    • 点赞 4
    • 收藏
    • 分享
    • 文章举报
    我是管小亮 博客专家 发布了216 篇原创文章 · 获赞 4537 · 访问量 66万+ 他的留言板 关注
    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: