getchar() 疑惑

来源:互联网 发布:甘肃广电网络官方网站 编辑:程序博客网 时间:2024/05/21 10:48

 因为最近正看从新看THE C  PROGRAMMING LANGUAGE 对getchar() 产生了疑惑,关于getchar()工作原理不了解,

按照 应该一次输入一个字符并显示,但是实际工作却不是,下面是查询的资料,感谢原创作者。

 

  看到CU上一个人发的帖子,我回答错误了,在网上找了些资料后对getchar()又有了一些新的了解。

getchar():
   我们用getchar()在控制台上取字符的时候,它首先要把所有取得的东西按照顺序放在内存的某个临时的地方,但我们输入回车时它会从这个地方开始在取字符,并按相同的顺序取,当取到回车时就是上次输入的最后一个字符,注意我们在一个程序里不论用多少getchar(),它都会存放在同一个地方,并且不断的向后增加,然后在用getchar()取的时候会从上次取的后面继续取,只要这个存储的地方有字符,那么我们用getchar()时控制台就不会停顿等待我们输入字符,只有当取到换行时才是表示这个地方完全空了,下次在用getchar()的时候控制台才会停顿等待用户输入字符!
getchar()返回的是int型.
[code]
          int c;
           while((c = getchar()) != EOF)
           {
                 ....
           }
[/code]
原因在于程序中的变量c被声明为char类型,而不是int类型。这意味着c无法容下所有可能的字符,特别是,可能无法容下EOF。因此,最终结果存在两种情况。一种可能是:某些合法的输入字符在被“截断”后使得c的取值与EOF相同;另一种可能是,c根本不可能取到EOF这个值。对于前一种情况,程序将在文件复制的中途终止;对于后一种情况,程序陷入一个死循环。实际上,还有可能存在第三种情况:程序表面上似乎能够正常工作,但完全是因为巧合。尽管函数getchar的返回结果在赋给char类型的变量c时会发生“截断”操作,尽管while语句中比较运算的操作数不是函数getchar的返回值,而是“被截断”的值c,然而令人吃惊的是许多编译器对上述表达式的实现并不正确。这些编译器确实对函数getchar的返回值作了“截断”处理,并把低端字节部分赋给了变量c。但是,它们在比较表达式中并不是比较c与EOF,而是比较getchar函数的返回值与EOF!编译器如果采取的是这种做法,上面的例子程序看上去就能够“正常”运行了。




一、getchar的两点总结:
1.getchar是以行为单位进行存取的。
当用getchar进行输入时,如果输入的第一个字符为有效字符(即输入是文件结束符EOF,Windows下为组合键Ctrl+Z,Unix/Linux下为组合键Ctrl+D),那么只有当最后一个输入字符为换行符'/n'(也可以是文件结束符EOF,EOF将在后面讨论)时,getchar才会停止执行,整个程序将会往下执行。譬如下面程序段:
while((c = getchar()) != EOF){
    putchar(c);
}

执行程序,输入:abc,然后回车。则程序就会去执行puchar(c),然后输出abc,这个地方不要忘了,系统输出的还有一个回车。然后可以继续输入,再次遇到换行符的时候,程序又会把那一行的输入的字符输出在终端上。


对于getchar,肯定很多初学的朋友会问,getchar不是以字符为单位读取的吗?那么,既然我输入了第一个字符a,肯定满足while循环(c = getchar()) != EOF的条件阿,那么应该执行putchar(c)在终端输出一个字符a。不错,我在用getchar的时候也是一直这么想的,但是程序就偏偏不着样执行,而是必需读到一个换行符或者文件结束符EOF才进行一次输出。

对这个问题的一个解释是,在大师编写C的时候,当时并没有所谓终端输入的概念,所有的输入实际上都是按照文件进行读取的,文件中一般都是以行为单位的。因此,只有遇到换行符,那么程序会认为输入结束,然后采取执行程序的其他部分。同时,输入是按照文件的方式存取的,那么要结束一个文件的输入就需用到EOF(Enf Of File). 这也就是为什么getchar结束输入退出时要用EOF的原因。

2.getchar()的返回值一般情况下是字符,但也可能是负值,即返回EOF。

这里要强调的一点就是,getchar函数通常返回终端所输入的字符,这些字符系统中对应的ASCII值都是非负的。因此,很多时候,我们会写这样的两行代码:
char c;
c = getchar();


这样就很有可能出现问题。因为getchar函数除了返回终端输入的字符外,在遇到Ctrl+D(Linux下)即文件结束符EOF时,getchar()的返回EOF,这个EOF在函数库里一般定义为-1。因此,在这种情况下,getchar函数返回一个负值,把一个负值赋给一个char型的变量是不正确的。为了能够让所定义的变量能够包含getchar函数返回的所有可能的值,正确的定义方法如下(K&R C中特别提到了这个问题):
int c;
c = getchar();

二、EOF的两点总结(主要指普通终端中的EOF)
1.EOF作为文件结束符时的情况:

EOF虽然是文件结束符,但并不是在任何情况下输入Ctrl+D(Windows下Ctrl+Z)都能够实现文件结束的功能,只有在下列的条件下,才作为文件结束符。
(1)遇到getcahr函数执行时,要输入第一个字符时就直接输入Ctrl+D,就可以跳出getchar(),去执行程序的其他部分;
(2)在前面输入的字符为换行符时,接着输入Ctrl+D;
(3)在前面有字符输入且不为换行符时,要连着输入两次Ctrl+D,这时第二次输入的Ctrl+D起到文件结束符的功能,至于第一次的Ctrl+D的作用将在下面介绍。
其实,这三种情况都可以总结为只有在getchar()提示新的一次输入时,直接输入Ctrl+D才相当于文件结束符。

2.EOF作为行结束符时的情况,这时候输入Ctrl+D并不能结束getchar(),而只能引发getchar()提示下一轮的输入。

这种情况主要是在进行getchar()新的一行输入时,当输入了若干字符(不能包含换行符)之后,直接输入Ctrl+D,此时的Ctrl+D并不是文件结束符,而只是相当于换行符的功能,即结束当前的输入。以上面的代码段为例,如果执行时输入abc,然后Ctrl+D,程序输出结果为:
abcabc

注意:第一组abc为从终端输入的,然后输入Ctrl+D,就输出第二组abc,同时光标停在第二组字符的c后面,然后可以进行新一次的输入。这时如果再次输入Ctrl+D,则起到了文件结束符的作用,结束getchar()。
如果输入abc之后,然后回车,输入换行符的话,则终端显示为:
abc         //第一行,带回车
abc         //第二行
               //第三行

其中第一行为终端输入,第二行为终端输出,光标停在了第三行处,等待新一次的终端输入。
从这里也可以看出Ctrl+D和换行符分别作为行结束符时,输出的不同结果。
EOF的作用也可以总结为:当终端有字符输入时,Ctrl+D产生的EOF相当于结束本行的输入,将引起getchar()新一轮的输入;当终端没有字符输入或者可以说当getchar()读取新的一次输入时,输入Ctrl+D,此时产生的EOF相当于文件结束符,程序将结束getchar()的执行。
【补充】本文第二部分中关于EOF的总结部分,适用于终端驱动处于一次一行的模式下。也就是虽然getchar()和putchar()确实是按照每次一个字符
进行的。但是终端驱动处于一次一行的模式,它的输入只有到“/n”或者EOF时才结束,因此,终端上得到的输出也都是按行的。
如果要实现终端在读一个字符就结束输入的话,下面的程序是一种实现的方法(参考《C专家编程》,略有改动)
/*Edit by Godbach
  CU Blog: http://blog.chinaunix.net/u/33048/
*/

#include <stdio.h>
#include <stdlib.h>

int
main(void)
{
    int c;
    /* 终端驱动处于普通的一次一行模式 */
    system("stty raw");
   
    /* 现在的终端驱动处于一次一个字符模式 */
    c = getchar();
   
putchar();
   
    /*
终端驱动处又回到一次一行模式 */
     system("stty cooked");
   
    return 0;
}


编译运行该程序,则当如入一个字符时,直接出处一个字符,然后程序结束。
由此可见,由于终端驱动的模式不同,造成了getchar()输入结束的条件不一样。普通模式下需要回车或者EOF,而在一次一个字符的模式下,则输入一个字符之后就结束了。

 

 

 

mian()
{
char c;
c=getchar();
putchar(c);
}
以上程序能输出第一个字符比如输入asd输出a
#include<stdio.h>
main()
{
char c;
while((c = getchar()) != 0)
putchar(c);
}
这个是ABD ABD
getchar是从缓存中读数据,也就是说,你输入a,程序并不反映,只是把a存到缓存中,直到你输入结束,输了回车,程序才反映。

//---------------------

第一个程序,键盘输入asd回车,getchar()函数读第一个字符,a,赋值给c,然后putchar(c)把结果输出,a。


第二个程序,输入asd回车,

getchar()读第一个字符a,赋值给c, c的值是a,(c=getchar())此时的值就是a,然后while进行判断,当然这个值不是0,即while的条件为真,执行putchar(c)输出a

由于while条件为真,循环继续,再读一个,就读了s,与上面描述一样,while条件依然是真,执行putchar输出s

第三次输出d


这时条件依然是真,再读一下,由于输入了回车,getchar读到没值了,c=0,结束循环

原创粉丝点击