zoukankan      html  css  js  c++  java
  • 深入了解scanf()/getchar()/gets()/getch,getche sunysl的专栏 博客频道 CSDN.NET

    深入了解scanf()/getchar()/gets()/getch,getche - sunysl的专栏 - 博客频道 - CSDN.NET

    深入了解scanf()/getchar()/gets()/getch,getche


    1人阅读
    评论(0)
    收藏
    举报

    ----------------------------------------------------
    | 问题描述一:(分析scanf()和getchar()读取字符) |
    ----------------------------------------------------
    scanf(), getchar()等都是标准输入函数,一般人都会觉得这几个函数非常简单,没什么特殊的。但是有时候却就是因为使用这些函数除了问题,却找不出其中的原因。下面先看一个很简单的程序:
    程序1:
    #include <stdio.h>
    int main()
    {
    char ch1, ch2;
    scanf("%c", &ch1);
    scanf("%c", &ch2);
    printf("%d %d/n", ch1, ch2);
    return 0;
    }
    或者是:
    #include <stdio.h>
    int main()
    {
    char ch1, ch2;
    ch1 = getchar();
    ch2 = getchar();
    printf("%d %d/n", ch1, ch2);
    return 0;
    }
    程序的本意很简单,就是从键盘读入两个字符,然后打印出这两个字符的ASCII码值。可是执行程序后会发现除了问题:当从键盘输入一个字符后,就打印出了结果,根本就没有输入第二个字符程序就结束了。例如用户输入字符'a', 打印结果是97,10。这是为什么呢?
    【分析】:
    首先我们呢看一下输入操作的原理,程序的输入都建有一个缓冲区,即输入缓冲区。一次输入过程是这样的,当一次键盘输入结束时会将输入的数据存入输入缓冲 区,而cin函数直接从输入缓冲区中取数据。正因为cin函数是直接从缓冲区取数据的,所以有时候当缓冲区中有残留数据时,cin函数会直接取得这些残留 数据而不会请求键盘输入,这就是例子中为什么会出现输入语句失效的原因!
    其实这里的10恰好是回车符!这是因为scanf()和getchar()函数是从输入流缓冲区中读取值的,而并非从键盘(也就是终端)缓冲区读取。而读 取时遇到回车(/n)而结束的,这个/n会一起读入输入流缓冲区的,所以第一次接受输入时取走字符后会留下字符/n,这样第二次的读入函数直接从缓冲区中 把/n取走了,显然读取成功了,所以不会再从终端读取!这就是为什么这个程序只执行了一次输入操作就结束的原因!

    ----------------------------------------------------
    | 问题描述二:(分析scanf()和gets()读取字符串) |
    ----------------------------------------------------

    首先我们看一下scanf()读取字符串的问题:
    程序2:
    #include <stdio.h>
    int main()
    {
    char str1[20], str2[20];
    scanf("%s",str1);
    printf("%s/n",str1);
    scanf("%s",str2);
    printf("%s/n",str2);
    return 0;
    }
    程序的功能是读入一个字符串输出,在读入一个字符串输出。可我们会发现输入的字符串中不能出现空格,例如:
    测试一输入:
    Hello world!
    输出:
    Hello
    world!
    【分析】到此程序执行完毕,不会执行第二次的读取操作!这个问题的原因跟问题一类似,第一次输入Hello world!后,字符串Hello world!都会被读到输入缓冲区中,而scanf()函数取数据是遇到回车、空格、TAB就会停止,也就是第一个scanf()会取出"Hello",而"world!"还在缓冲区中,这样第二个scanf会直接取出这些数据,而不会等待从终端输入。

    测试二:
    Hello[Enter]
    Hello[输出]
    world[Enter]
    world[输出]
    【分析】程序执行了两次从键盘读入字符串,说明第一次输入结束时的回车符被丢弃!即:scanf()读取字符串会舍弃最后的回车符!


    我们再看一下gets()读取字符串的情况:
    scanf来读取一个字符串时,字符串中是不可以出现空格的,一旦出现空格,后面的数据就会舍弃残留在缓冲区中。其实有另外一个函数是可以接受空格的,那就是gets(),下面我们看一下这个函数的应用,我们把程序2改动一下:
    程序3:
    #include <stdio.h>
    int main()
    {
    char str1[20], str2[20];
    gets(str1);
    printf("%s/n",str1);
    gets(str2);
    printf("%s/n",str2);
    return 0;
    }
    测试:
    Hello world! [输入]
    Hello world! [输出]
    12345 [输入]
    12345 [输出]
    【分析】显然上一个程序的执行情况不同,这次程序执行了两次从键盘的读入,而且第一个字符串取了Hello world! 接受了空格符,而没有像上一个程序那样分成了两个字符串!所以如果要读入一个带空格符的字符串时因该用gets(), 而不宜用scanf()!


    --------------------------------------------------------
    | 问题描述三:(getchar()暂停程序,查看程序执行结果)|
    --------------------------------------------------------
    不知道大家有没有遇到过这样的问题,有的编译器程序执行完后的结果界面不会停下而是一闪就没了,以至于看不到执行结果。所以很多人在程序最后加上 getchar()语句,目的是想让程序执行完后停下来,等待从终端接收一个字符再结束程序。可是发现有时候这样根本没用,程序照样跳出去了。这是为什么 呢?
    【分析】原因跟上面例子讲的一样,是因为输入缓冲区中还有数据,所以getchar()会成果读到数据,所以就跳出了!

     

    ------------------
    | 【总结】 |
    ------------------

    第一:要注意不同的函数是否接受空格符、是否舍弃最后的回车符的问题!
    读取字符时:
    scanf()以Space、Enter、Tab结束一次输入,不会舍弃最后的回车符(即回车符会残留在缓冲区中);
    getchar()以Enter结束输入,也不会舍弃最后的回车符;
    读取字符串时:
    scanf()以Space、Enter、Tab结束一次输入
    gets()以Enter结束输入(空格不结束),接受空格,会舍弃最后的回车符!

    第二:为了避免出现上述问题,必须要清空缓冲区的残留数据,可以用以下的方法解决:
    方法1:C语言里提供了函数清空缓冲区,只要在读数据之前先清空缓冲区就没问题了!
    这个函数是fflush(stdin)。
    方法2:自己取出缓冲区里的残留数据。
    (说实话这个语句我也没看懂,呵呵!为什么格式控制是这样的!希望高手指点一下!)
    scanf("%[^/n]",string);

    |----------- 文章为作者原创,转载请注明出处或作者! ------------ |

     

    getch,getche和getchar区别

    首先不要忘了,要用getch()必须引入头文件conio.h,以前学C语言的时候,我们总喜欢用在程序的末尾加上它,利用它来实现程序运行完了暂停不 退出的效果。如果不加这句话,在TC2.0的环境中我们用Ctrl+F9编译并运行后,程序一运行完了就退回到TC环境中,我们根本来不及看到结果,这时 要看结果,我们就要按Alt+F5回到DOS环境中去看结果,这很麻烦。而如果在程序的结尾加上一行getch();语句,我们就可以省掉会DOS看结果 这个步骤,因为程序运行完了并不退出,而是在程序最后把屏幕停住了,按任意键才退回到TC环境中去。

    那我们来看看getch()到底起的什么作用,getch()实际是一个输入命令,就像我们用cin>>的时候程序会停下来等你输入,和 cin不同的是,getch()的作用是从键盘接收一个字符,而且并不把这个字符显示出来,就是说,你按了一个键后它并不在屏幕上显示你按的什么,而继续 运行后面的代码,所以我们在C++中可以用它来实现“按任意键继续”的效果,即程序中遇到getch();这行语句,它就会把程序暂停下来,等你按任意 键,它接收了这个字符键后再继续执行后面的代码。

    你也许会问,为什么我们在C++中就没有在程序的末尾加上getch(),解释是,软件总是不断更新的,不好的地方当然要进行改正,getch()加 在程序末尾,它又不赋值给任何变量,所以它在这个地方完全是垃圾代码,程序无关。C++中考虑到这一点,于是在每次程序运行完了并不退出,而是自动把屏 幕停下来,并显示“press any key...”叫你按任意键退出,这就好比C++在它的环境中运行程序,在程序的末尾自动加上了一行getch();语句,并且在这行语句前还添加了一行 输出语句cout<<"press any key...";来提示你程序结束了,按任意键继续。实际上我们编译好的程序在程序结束了本身是不会停下来的,我们可以在编译产生的Debug目录中找到 这个编译好的应用程序(扩展名exe),在文件夹中双击运行它,你会发现屏幕闪了一下MS-DOS窗口就关闭了,因为程序运行完就自动退出了,回到了 windows环境,当然,如果我们在DOS环境中运行这个程序,我们就可以直接在看到DOS屏幕上看到程序运行结果,因为程序运行完后并不清屏。

    还有一个语句,和getch()很相似,getche(),它也需要引入头文件conio.h,那它们之间的区别又在哪里呢?不同之处就在于getch()无返回显示,getche()有返回显示。怎么说呢?我举个例子你就明白了。

    --------------------------------------

    #include <stdio.h>
    #include <conio.h>
    void main()
    {
    char ch;
    for(int i=0;i<5;i++)
    {
    ch=getch();
    printf("%c",ch);
    }
    }

    --------------------------------------

    这里输入输出我用的是C的函数库,没有用C++的iostream.h,这个我等会再说。首先这是个连续5次的循环来实现5次停 顿,等待我们输入,我们编译并运行这个程序,假设我们分别输入abcde,屏幕上显示的结果是abcde,这个abcde并不是在ch=getch(); 中输出的,我们把printf("%c",ch);这行语句去掉,就会发现我们按5次任意键程序就结束了,但屏幕上什么都没有显示。

    (这里要注意一点,就是关于回车的问题,当我们输入a[Enter]之后,屏幕上会另起一行显示a,要注意,其实这里显示的不只是a,而是 a[Enter],这里[Enter]也算一个字符,所以当我们继续输入b[Enter]后,显示b,当再输入c[Enter]时,5个字符已满,多出一 个[Enter],所以屏幕上只显示c,我用的是C-Free,可以看到:

    a
    a
    b
    b
    c
    c请按任意键继续. . .

    这里“请按任意键继续. . .”就跟c显示在了同一行,可知c后的[Enter]并没有输出,然后就退出了。为了验证这个,我们可以在第一行先输入一个[Enter],可以看到光标 到了第3行,然后我们再输入abcde,回车之后,只输出了abcd,因为这4个,加上前一个[Enter],5个字符已满。)

    然后我们在把代码中的getch()换成getche()看看有什么不同,我们还是分别输入abcde,这时屏幕上显示的结果是 aabbccddee,我们把printf("%c",ch);这行语句再去掉看看,显示的结果就是abcde了,说明程序在执行 ch=getche();这条语句的时候就把我们输入的键返回显示在屏幕上,有无回显就是它们的唯一区别。

    (读到此,有一处未明,就是二者显示的差别,前者输入abcde后,回车把abcde显示在下一行,而后者,输入a后,马上就显示a,输入b后马上显示b。我觉得按程序的执行顺序来说,后者应该是正确的,即getche有回显,输入后马上执行printf语句。

    后苦苦思索,方才明白,我们在前者,也就是使用getch时,我们之所以能看到我们输入的abcde,就是printf语句的功劳,因为如果没有这句,我们就什么也看不到了,到此方大彻大悟啊,^_^)

    好了,我们再来说说为什么不用C++函数库的原因。你可以试试把这个程序改成C++的形式(原来程序很乱,我依然用C写的):

    --------------------------------------

    #include <stdio.h>
    #include <conio.h>
    void main()
    {
    char ch='1';
    while(ch=='1')
    {
    printf("/n按 1 继续循环,按其他键退出!");
    ch=getch();
    }
    printf("/n退出程序!");
    }

    --------------------------------------

    我们可以在这个循环体中添加我们想要的功能,程序中按*继续循环,其他任意键退出,而且利用getch()无回显的特性,我们不管按什么,都不会在屏 幕上留下痕迹,使我们的界面达到美观效果,如果还有更好的办法实现这个功能,我可能就不会在这里提这么多了。如果你真的有更好的办法,请一定告诉我,谢 谢!

    下面我把别人网页上的几个例子转载如下:

    --------------------------------------

    //例一:这个例子是为了说明getch()和getche()的区别 #include #include

    //这里讲个小故事:因为这个代码是在别人网页上的,别人用的C环境,可能是不需要conio.h头文件就可以用getch();(我就不清楚了),也可能是忘了写,网页上的源代码没有#include这一行,

    void main()

    {

    char c, ch;

    c=getch();

    putchar(c);

    ch=getche();

    putchar(ch);

    printf("/n/n");

    }

    --------------------------------------

    //例二:这个例子是演示交互输入的过程中完成暂停功能

    #include <stdio.h>
    #include <conio.h>
    void main()
    {
    char c, s[20];
    printf("Name:");
    gets(s);
    printf("Press any key to continue.../n/n");
    getch();
    printf("/n/n");
    }

    --------------------------------------

    //例三:getchar()函数也是从键盘上读入一个字符,并带回显。它前面两个函数的区别在于:

    //getchar()函数等待输入直到按回车才结束,回车前的所有输入字符都会逐个显示在屏幕上。

    //但只有第一个字符作为函数的返回值。

    #include <stdio.h>
    void main()
    {
    char c;
    c=getchar(); //getchar()在这里它只返回你输入字符串的第一个字符,并把返回值赋值给c
    putchar(c);
    }

    本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/jiazhen198239/archive/2007/11/08/1873473.aspx

  • 相关阅读:
    how to pass a Javabean to server In Model2 architecture.
    What is the Web Appliation Archive, abbreviation is "WAR"
    Understaning Javascript OO
    Genetic Fraud
    poj 3211 Washing Clothes
    poj 2385 Apple Catching
    Magic Star
    关于memset的用法几点
    c++ 函数
    zoj 2972 Hurdles of 110m
  • 原文地址:https://www.cnblogs.com/lexus/p/2547257.html
Copyright © 2011-2022 走看看