getchar()是stdio.h中的库函数,它的作用是从stdin流中读入一个字符,也就是说,如果stdin有数据的话不用输入它就可以直接读取了。
getch()和getche()是conio.h中的库函数,它的作用是从键盘接收字符。getchar带有显示。与前面两个函数的区别在于: getchar()函数等待输入直到按回车才结束(前提是缓冲区没有数据),回车前的所有输入字符都会逐个显示在屏幕上。但只有第一个字符作为函数的返回值。
#include<stdio.h>
#include<conio.h> /*我在gcc里没找到这个头文件,可能改名或者取消了吧.*/
void main()
{
    char c;
    c=getchar(); /*从键盘读入字符直到回车结束*/
    //getchar()在这里它只返回你输入字符串的第一个字符,并把返回值赋值给c
    putchar(c); /*显示输入的第一个字符*/
    printf("\n\n");
}
这个程序你运行一下,相信你又会有疑问了。这个就是从缓冲区中读取了例子。第一次getchar()时,确实需要人工的输入,但是如果你输了多个字符,以后的getchar()再执行时就会直接从缓冲区中读取了。
#include<stdio.h>
#include<conio.h>
void main()
{
    char c;
    while ((c=getchar())!='\n') /*每个getchar()依次读入一个字符*/
        printf("%c",c); /*按照原样输出*/
    printf("\n\n");
}
程序运行时,首先停下来,等你输入一串字符串,输入完毕后,它把你输入的整个字符串都输出来了,不是说getchar()只返回第一个字符么,这里怎么?
因为我们输入的字符串并不是取了第一个字符就把剩下的字符串丢掉了,它还在我们的内存中,好比,开闸放水,我们把水放到闸里去以后,开一次闸就放掉一点,开一次就放掉一点,直到放光了为止,这里开闸动作就相当于调用一次getchar()。我们输入的字符串也是这么一回事,首先我们输入的字符串是放在内存的缓冲区中的,我们调用一次getchar()就把缓冲区中里出口最近的一个字符输出,也就是最前面的一个字符输出,输出后,就把它释放掉了,但后面还有字符串,所以我们就用循环把最前面的一个字符一个个的在内存中释放掉,直到不满足循环条件退出为止。
例子中循环条件里的'\n'实际上就是你输入字符串后的回车符,所以意思就是说,直到遇到回车符才结束循环,而getchar()函数就是等待输入(或缓冲区中的数据)直到按回车才结束,所以实现了整个字符串的输出。当然,我们也可以把循环条件改一下,比如
while ((c=getchar())!='a'),什么意思呢,意思就是遇到字符'a'就停止循环,当然意思是如果你输入“12345a213123\n”那么只会输出到a,结果是12345a。
再次注意:用getchar()它是从“流”中间去读取,所以第一个getchar()接受的是刚刚中断的流队列中即将出列的第一个字符(不限于回车符,上面举过例子了),如果流队列不为空,执行getchar()就继续放水,直到把回车符也放空为止,空了之后再在执行getchar()就停下等待你的输入了;我们用getch()为什么每次都是等待用户的输入呢?因为getch()是从键盘接收,即时的接收,并不是从stdin流中去读取数据。
补充:按键盘上的回车产生了2个字符:回车符('\r')和换行符('\n')。回车'\r'(CR:carriage return:倒车)使光标回到这行的首部,换行符('\n')(new line)然后再换行。所以当输入字符'w',并按下回车键以后。首先得到回车符。那个getchar函数结束了。但是还存在一
个换行符。所以如果用getchar()来做判断的时候。最好再写一次getchar()清除缓冲区的'\n'.
如何清空输入缓冲区的内容?
如果我想让getchar()每次都能够等待用户输入的话就要清空缓冲区,下面就介绍方法(不同平台)
C标准规定fflush()函数是用来刷新输出(stdout)缓存的。对于输入(stdin),它是没有定义的。但是有些编译器也定义了fflush( stdin )的实现,比如微软的VC。其它编译器是否也定义了fflush( stdin )的实现应当查找它的手册。GCC编译器没有定义它的实现,所以不能使用fflush( stdin )来刷新输入缓存。
对于没有定义fflush( stdin )的编译器,可以使用fgets()函数来代替它(比用getchar()、scanf()等函数通用性好)。可以这样忽略输入流中留下的回车等其它输入,从而使下一次的输入总保持一个“干净”的状态。(这个是任何平台下都可以的)
char sbuf[1024];
// ...
fgets( sbuf, 1024, stdin );
// ...
在windows 的vc下面就可以这样了:
for(int i=0;i<10;++i)
{
    char ch=getchar();
    fflush(stdin); //每次都会有等待状态了
}
这里说到gcc编译器没有定义fflush的实现,我们一般用getchar();来清除缓冲区.
下面是我的讨论:
先来一段code:
#include <stdio.h>
main()
{
    char c;
    for(;(c=getchar())!='a';)
        printf("%c",c);
    getchar();
    c=getchar();
    printf("%c",c);
}
输入:
ssss回车
得到:
ssss
光标处(等待输入)
说明:此时程序没有结束,进行到for循环,因为并没有字符a出现,所以还没跳出for循环.键入回车后,getchar依次从缓冲区内取出(for循环):'s''s''s''s''\n'
如果我们输入:
ssssa回车
得到:
ssss光标处(等待输入)
说明:程序已经跳出for循环,但是由于我们用getchar();清除了换行'\n',后面第7句c=getchar();需要你输入一个字符(因为ssssa后面并没有新的字符),所以程序仍然没有结束.如果我们注释掉getchar();这一句,那么得到:
ssss
光标处(程序结束)
这个输入ssssa是的回车中的换行符'\n'就被c=getchar();这一句读取并输出了。
总结:
键盘输入的字符都存到缓冲区内,一旦键入回车,getchar就进入缓冲区读取字符,一次只返回第一个字符作为getchar函数的值,如果有循环或足够多的getchar语句,就会依次读出缓冲区内的所有字符直到'\n'.要理解这一点,之所以你输入的一系列字符被依次读出来,是因为循环的作用使得反复利用getchar在缓冲区里读取字符,而不是getchar可以读取多个字符,事实上getchar每次只能读取一个字符.如果需要取消'\n'的影响,可以用getchar();来清除,这里getchar();只是取得了'\n'但是并没有赋给任何字符变量,所以不会有影响,相当
于清除了这个字符.还要注意的是这里你在键盘上输入ssss看到的回显正是来自于getchar的作用,如果用getch就看不到你输入了什么.再引一篇文章:
http://www.cnblogs.com/biser/archive/2004/09/23/45704.aspx
1.机理
你键盘输入了东西,而此时你又没有用程序去getchar她,请问这个时候你按的键的状态保存在何处?为什么你一会儿去getchar的时候能得到呢
(例子好举,你先做一个1分钟延迟,然后再getchar,会发现一分钟前按的东西会显示出来)
实际上是输入设备->内存缓冲区->程序getchar
你按的键是放进缓冲区了,然后供程序getchar
你有没有试过按住很多键然后等一会儿会滴滴滴滴响,就是缓冲区满了,你后头按的键没有存进缓冲区.
2.getchar()和getch()
getchar是回车以后才进缓冲区
getch是每次都进缓冲区
用你的程序来说(我怎么觉得应该是\n不是/n),其实你输入computer,没按回车之前, 运行都停止在getchar()里头,根本没有进入循环,自然也没有运行printf.当你一按回车,才从getchar出来,然后以后因为键盘缓冲区里头有东西,就一个一个字符getchar出来了.想立刻回显,用getch就好了
3.scanf
scanf这个库函数比较奇怪,而且存在一定的缺陷,所以很多人都不用了.
scanf输入字符串,整型,实型等数据判断的方式都一样,回车,空格,tab键都认为是一个数据的结束,当然,字符的话,一个字符就是结束了,回车,空格等都有对应的ascii码,所以用scanf输入字符时要小心这些东东被当成字符输进去,而输入字符串和整型,实型等数据时这些都被当成分隔符而不会被输入到字符数组或变量里.
说了这么多举几个例子:
#include <stdio.h>
int main()
{
    char n1[10];
    char n2[10];
    scanf("%s",n1);
    scanf("%s",n2);
    printf("n1=%s,n2=%s",n1,n2);
}
输入:
hello回车
world回车
得到:
n1=hello,n2=wolrd光标处(程序结束)
这里hello后面就是输入再多个回车,空格也不会被赋值到n2中的,因为他们只是分隔符.
如果输入:
hello回车
光标处(等待输入)
说明回车被认成分隔符,所以程序还要你输入一个字符串来赋给n2.
其实这时缓冲区里是有一个'\n'被留下来的,程序改成这样:
#include <stdio.h>
int main()
{
    char n1[10];
    char n2[10];
    char n3,n4;
    scanf("%s",n1);
    scanf("%s",n2);
    printf("n1=%s,n2=%s",n1,n2);
    n3=getchar();
    printf("%c",n3);
    //n4=getchar();
    //printf("%c",n4);
}
输入:
hello回车
world回车
得到:
hello
world
n1=hello,n2=wolrd
光标处(程序结束)
如果取消最后两行的注释,同样的输入得到:
hello
world
n1=hello,n2=wolrd
光标处(等待输入)
说明此时缓冲区内只有一个'\n',第二个getchar就需要你再输入一个字符了,缓冲区内已经没有字符了.
scanf不会把回车空格赋给字符串但是会赋给字符,就如同getchar一样,这时就要考虑'\n'的存在了.
比如:
#include <stdio.h>
int main()
{
    char n1[10];
    char n2;
    scanf("%s",n1);
    scanf("%c",&n2);
    printf("n1=%s,n2=%d",n1,n2);
}
输入:
hello回车
得到:
n1=hello,n2=10光标处(程序结束) //10是'\n'的ascii码.
如果输入:
hello 空格回车(一定要有回车,因为scanf也是要等回车,准确说是'\r'才会去读缓冲区的.)
得到:
n1=hello,n2=32光标处(程序结束) //32是空格的ascii码.
再罗嗦一下,如果最后一句输入n2=%d改成n2=%c,则输入:
hello回车
得到:
n1=hello,n2=
光标处(程序结束)
是不是和getchar一样可以把'\n' 读出来呢.
总结:
如果scanf输入的不是字符,那么分隔符为回车,空格,tab键时,两个数据之间的分隔符只是起区别两个数据的作用,把分隔好的两个数据分别赋值到各自定义好的变量或数组中去,两个数据之间的分隔符被从缓冲区读出但是不起任何作用,当然最后一个'\n'会被留在缓冲区内,除非用getchar();或scanf("%c",&c);把它读出来.
回车是一定要有的,不管getchar还是scanf只要是通过缓冲区输入数据的函数都是等待回车键'\r'出现才进入缓冲区的.
再来个整型数据,字符串,字符的混合例子:
#include <stdio.h>
int main()
{
    int a,b,c;
    char n1[10];
    char n2,n3;
    scanf("%d%d",&a,&b);
    scanf("%c",&n2);
    scanf("%d",&c);
    scanf("%s",n1);
    scanf("%c",&n3);
    printf("a=%d,b=%d,n2=%c,c=%d,n1=%s,n3=%c",a,b,n2,c,n1,n3);
}
输入:
12(若干空格或回车就不影响结果,这里用了回车)
34(这里还要求输入,因为scanf只得到了一个整型数据,而缓冲区内没有整型数据了。要有回车或空格表示这个数据结束了,留下来的空格或回车被下个%c接受,这里用了回车,可以试一下空格)
45 jfdkjfa(回车)
得到:
a=12,b=34,n2=
,c=45,n1=jfdkjfa,n3=
光标处(程序结束)
这里说明一下过程:在前两个整型数据输入时,两个数据之间无论是回车还是若干空格都被scanf当做分隔符,scanf读到分隔符(回车或空格)时,把第一个整型数据送到变量a中,缓冲区中留下分隔符和下面的整型数据,这时scanf再读当然先读分隔符,但是要求输入的还是整型数据(%d),所以分隔符被忽略,如果这时要求输入字符%c(不是字符串%s),那么分隔符将以一个字节的形式送到字符变量里,就如同这里的n2.同理可以知道c和n1的保存过程,最后的n3正是接收了输入时的最后一个回车.
如果看到这里你都理解了那么看最后一个例子:
#include <stdio.h>
main(){
    int a;
    char ch;
    scanf("%d",&a);
    ch=getchar();
    printf("%d,%c",a,ch);
}
输入:
95回车
得到:
95,
光标处(程序结束)
很明显这是由于分隔符(回车)被getchar读取并输出了,如果加入一句:getchar();
#include <stdio.h>
main(){
    int a;
    char ch;
    scanf("%d",&a);
    getchar();
    ch=getchar();
    printf("%d,%c",a,ch);
}
输入:
95回车
c回车
得到:
95,c光标处(程序结束)

getchar,scanf以及缓冲区的更多相关文章

  1. getchar、scanf以及缓冲区的概念

      1.getchar()是stdio.h中的库函数,它的作用是从stdin流中读入一个字符,也就是说,如果stdin有数据的话不用输入它就可以直接读取了.       getch()和getche( ...

  2. getchar与putchar缓冲区以及字符串数组、指针

    getchar与putchar缓冲区 有下面的语句段: while ((s = getchar()) != '\n'){ putchar(s); putchar("\n"); } ...

  3. 详解getchar()函数与缓冲区

    1.首先,我们看一下这段代码: 它的简单意思就是从键盘读入一个字符,然后输出到屏幕.理所当然,我们输入1,输出就是1,输入2,输出就是2. 那么我们如果输出的是12呢? 它的输出是1. 这里我们先简单 ...

  4. 关于cin,getchar(),scanf()的注意事项(转)

      问题描述一:(分析scanf()和getchar()读取字符) scanf(), getchar()等都是标准输入函数,一般人都会觉得这几个函数非常简单,没什么特殊的.但是有时候却就是因为使用这些 ...

  5. getchar(),scanf(),gets(),cin,输入字符串

    #include<iostream>#include<stdio.h>#include<string.h>#include<string>using n ...

  6. 用scanf清空缓冲区 对比fflush

    fflush会将缓冲数据打印到屏幕或者输出磁盘,scanf将丢弃. 如上图.

  7. scanf 与 cin 的区别

    在论坛上看到有人提出一个如下的问题,在此总结一下. 原问题: http://topic.csdn.net/u/20110414/22/90d0606c-9876-48e4-9b69-bd8bd8a41 ...

  8. linux printf和fork()问题小结

    总结如下: printf("father begin"); pid_t pid; pid = fork(); ) { ) { printf("father out&quo ...

  9. 关于scanf、getchar、getch、getche缓冲区分析——C语言

    缓冲区 根据数据刷新的时机可以将缓冲区的类型分为:全缓冲.行缓冲.无缓冲 (注意:Windows下的输出设备没有缓冲区,意思是printf是无缓冲的,但是在Linux下printf就是行缓冲的,至于为 ...

随机推荐

  1. sql语句优化技巧

    1.对查询进行优化,要尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索 ...

  2. 初识Quartz(一)

    首先需要一个任务: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package quartz_proj ...

  3. Mysql之sync-binlog参数

    Mysql开启bin-log日志使用bin-log时,默认情况下,并不是每次执行写入就与硬盘同步,这样在服务器崩溃是,就可能导致bin-log最后的语句丢失. 可以通过这个参数来调节,sync_bin ...

  4. poj 2942 Knights of the Round Table(无向图的双连通分量+二分图判定)

    #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #includ ...

  5. Scrapy爬虫入门系列3 将抓取到的数据存入数据库与验证数据有效性

    抓取到的item 会被发送到Item Pipeline进行处理 Item Pipeline常用于 cleansing HTML data validating scraped data (checki ...

  6. Eclipse 创建 Java 接口

    打开新建 Java 接口向导 新建 Java 接口向导可以创建新的 Java 接口.打开向导的方式有: 点击 File 菜单并选择 New > Interface 在 Package Explo ...

  7. 在iframe的父级作用域操作,ifame中的元素。。

    frames["iframe的name"].SchDatas SchDatas为方法名js中 frames["iframe的name"].document.ge ...

  8. 【剑指Offer面试题】 九度OJ1518:反转链表

    与其非常快写出一段漏洞百出的代码,倒不如细致分析再写出鲁棒的代码. 提前想好測试用例(输入非空等等)进行測试改动代码. 题目链接地址: http://ac.jobdu.com/problem.php? ...

  9. Android无线测试之—UiAutomator UiDevice API介绍四

    拖拽与滑动 一.概念介绍: 1)拖拽:将组建从一个坐标移动到另一个坐标 2)移动:从一二坐标点移动到另一个坐标点 3)步长:从一点滑动到另一点使用的时间 二.拖拽与滑动的相关API: 返回值 方法名 ...

  10. 【BZOJ3995】[SDOI2015]道路修建 线段树区间合并

    [BZOJ3995][SDOI2015]道路修建 Description  某国有2N个城市,这2N个城市构成了一个2行N列的方格网.现在该国政府有一个旅游发展计划,这个计划需要选定L.R两列(L&l ...