C语言入门教程
OutOfMemory.CN技术专栏-> C语言-> C语言入门教程-> 结合缓冲区谈谈C语言getchar()、getche()、getch()的区别

结合缓冲区谈谈C语言getchar()、getche()、getch()的区别

本文将用到C语言缓冲区的概念,如果您不了解缓冲区,请查看:C语言缓冲(缓存)三个函数的对比--缓冲区头文件回显getchar()有缓冲区stdio.h有回显getch()无缓冲区conio.h无回显g
本文将用到C语言缓冲区的概念,如果您不了解缓冲区,请查看:C语言缓冲(缓存)

三个函数的对比
-- 缓冲区 头文件 回显
getchar() 有缓冲区 stdio.h 有回显
getch() 无缓冲区 conio.h 无回显
getche() 无缓冲区 conio.h 有回显

getchar()函数

先来看一下getchar(),其原型为:
    int getchar(void);

当程序调用getchar()函数时,程序就等着用户按键,用户输入的字符被存放在键盘缓冲区中,直到用户按回车为止(回车字符也放在缓冲区中)。当用户键入回车之后,getchar()函数才开始从键盘缓冲区中每次读入一个字符。也就是说,后续的getchar()函数调用不会等待用户按键,而直接读取缓冲区中的字符,直到缓冲区中的字符读完后,才重新等待用户按键。

通俗一点说,当程序调用getchar()函数时,程序就等着用户按键,并等用户按下回车键返回。期间按下的字符存放在缓冲区,第一个字符作为函数返回值。继续调用getchar()函数,将不再等用户按键,而是返回您刚才输入的第2个字符;继续调用,返回第3个字符,直到缓冲区中的字符读完后,才等待用户按键。

下边的一个实例,会让你有深刻的体会:
#include <stdio.h>
int main()
{
    char c;
    //第一次调用getchar()函数
    //程序执行时,您可以输入一串字符并按下回车键,按下回车键后该函数才返回
    c=getchar();
    //显示getchar()函数的返回值
    printf("%c\n",c);
    //暂停
    system("PAUSE");
    while((c=getchar())!='\n')
    {
        printf("%c",c);
    }
    //暂停
    system("PAUSE");
    return 0;
}
这段小代码很简单,并且在代码内部都有注释。

getchar()函数的执行就是采用了行缓冲。第一次调用getchar()函数,会让程序使用者(用户)输入一行字符并直至按下回车键 函数才返回。此时用户输入的字符和回车符都存放在行缓冲区。

再次调用getchar()函数,会逐步输出行缓冲区的内容。

请再看下面一个例子:
#include <stdio.h>
int main()
{
    char ch1;
    char ch2;

    ch1 = getchar();
    ch2 = getchar();
    printf("%d  %d", ch1, ch2);
    return 0;
}
程序的本意很简单,就是从键盘读入两个字符,然后打印出这两个字符的ASCII码值。可是执行程序后会发现出了问题:当从键盘输入一个字符后,就打印出了结果,根本就没有输入第二个字符程序就结束了。例如用户输入字符’a', 打印结果是97,10。这是为什么呢?

getchar()函数是从输入流缓冲区中读取数据的,而不是从键盘(终端)缓冲区读取。当读取遇到回车(\n)结束时,这个'\n'会一起读入到输入流缓冲区的,所以第一次接收输入时取走字符后会留下字符\n,这样第二次getchar()直接从缓冲区中把\n取走了,显然读取成功了,所以不会再从终端读取!其实这里的10恰好是回车符!这就是为什么这个程序只执行了一次输入操作就结束的原因!

getch()和getche()函数

在TC2.0时代,C程序员总是喜欢在程序末尾加上getch(),来实现程序运行完了暂停不退出的效果。如果不这样做,在TC2.0的环境中Ctrl+F9编译并运行后会立即退出程序,根本来不及看到结果。这时如果要看结果,就要按Alt+F5回到DOS环境中去,很麻烦。而如果在程序的结尾加上一行getch();语句,就可以省掉回DOS看结果这个步骤,因为程序运行完了并不退出,而是在程序最后把屏幕停住了,按任意键才退出程序。

实际上,getch()的作用是从键盘接收一个字符,且不带回显。就是说,你按了一个键后它并不在屏幕上显示你按的什么,而继续运行后面的代码,所以在C语言中可以用它来实现“按任意键继续”的效果,即程序中遇到getch();语句,就会停下来,等你按任意键,它接收了这个字符键后再继续执行后面的代码。

getche()和getch()很相似,它也需要引入头文件conio.h,它们之间的区别就在于:getch()无回显,getche()有回显。请看下面的例子:
#include<stdio.h>
#include<conio.h>
void main()
{
    char ch;
    int i;
    for(i=0;i<5;i++)
    {
        ch=getch();
        printf("%c",ch);
    }
}
首先这是个连续5次的循环来实现5次停顿,等待你输入。编译并运行这个程序,假设输入的是abcde,那么屏幕上显示的结果也是abcde,这个abcde并不是在ch=getch();中输出的。把printf("%c",ch);这行语句去掉,就会发现按5次任意键程序就结束了,但屏幕上什么都没有显示。

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

请大家再看下面一个例子:
#include<stdio.h>
#include<conio.h>
void main()
{
    char ch='*';
    while(ch=='*')
    {
        printf("\n按 * 继续循环,按其他键退出!");
        ch=getch();
    }
    printf("\n退出程序!");
}
你可以在这个循环体中添加你想要的功能,程序中按*继续循环,其他任意键退出,而且利用getch()无回显的特性,不管你按什么键,都不会在屏幕上留下痕迹,使你的界面达到美观效果。

还有getchar是很值得研究的:getchar()是stdio.h中的库函数,它的作用是从stdin流(标准输入流)中读入一个字符,也就是说,如果stdin有数据的话不用输入它就可以直接读取了。而getch()和getche()是conio.h中的库函数,它的作用是从键盘接收字符。

与前面两个函数的区别在于: getchar()函数等待输入直到按回车才结束(前提是缓冲区没有数据),回车前的所有输入字符都会逐个显示在屏幕上。但只有第一个字符作为函数的返回值。
#include<stdio.h>
#include<conio.h>
void main()
{
    char c;
    // 从键盘读入字符直到回车结束
    //getchar()在这里它只返回你输入字符串的第一个字符,并把返回值赋值给c
    c=getchar();
    // 显示输入的第一个字符
    putchar(c);
}
看到这个程序,相信你肯定会有疑问。这个就是从缓冲区中读取字符的例子。第一次getchar()时,确实需要人工的输入,但是如果你输了多个字符,以后的getchar()再执行时就会直接从缓冲区中读取了。
#include<stdio.h>
#include<conio.h>
void main()
{
    char c;
    // 每个getchar()依次读入一个字符
    while ((c=getchar())!='\n')
        printf("%c",c);  // 按照原样输出
}
程序运行后,首先停下来,等待输入一个字符串,输入完毕后,它会把你输入的整个字符串都输出来了。

这是为什么?getchar()不是只返回第一个字符么,这里为什么全部输出了?

因为我们输入的字符串并不是取了第一个字符就把剩下的字符串丢掉了,它还在我们的缓冲区中,就好像开闸放水,你把水放到闸里去以后,开一次闸就放掉一点,开一次就放掉一点,直到放光了为止,这里开闸动作就相当于调用一次getchar()。我们输入的字符串也是这么一回事,首先我们输入的字符串是放在内存的缓冲区中的,我们调用一次getchar()就把缓冲区中里出口最近的一个字符输出,也就是最前面的一个字符输出,输出后,就把它释放掉了,但后面还有字符串,所以我们就用循环把最前面的一个字符一个个的在内存中释放掉,直到不满足循环条件退出为止。

例子中循环条件里的'\n'实际上就是你输入字符串后的回车符,所以意思就是说,直到遇到回车符才结束循环,而getchar()函数就是等待输入(或缓冲区中的数据)直到按回车才结束,所以实现了整个字符串的输出。当然,我们也可以把循环条件改一下,比如while ((c=getchar())!='a'),就是遇到字符'a'就停止循环,当然意思是如果你输入“12345a213123/n”那么只会输出到a,结果是12345a。

请注意:用getchar()是到标准输入流中读取数据,所以第一个getchar()接受的是刚刚中断的流队列中即将出列的第一个字符(不限于回车符,上面举过例子了),如果流队列不为空,执行getchar()就继续放水,直到把回车符也放空为止,空了之后再在执行getchar()就停下等待你的输入了。

那么为什么getch()每次都是等待用户的输入呢?因为getch()是从键盘接收,即时的接收,并不是从stdin流(标准输入流)中去读取数据。
© 内存溢出 OutOfMemory.CN