首页 » C语言解惑 » C语言解惑全文在线阅读

《C语言解惑》20.1 getchar函数的返回类型不是字符

关灯直达底部

【例20.1】下面程序的是把输入复制到输出,分析程序中的错误。


#include <stdio.h>int main( void ){      while (getchar()!=EOF)             putchar(getchar());      printf(/"n/");      return 0;}  

【解答】当程序调用getchar时,程序就等着用户输入,如果用户输入不止一个字符,这些字符都会被存放在键盘缓冲区中。直到用户按回车(回车字符也放在缓冲区中)时,getchar才开始从stdin流中每次读入一个字符。等到缓冲区中的字符读完后,再等待用户输入。

在while语句里面的getchar函数用来判断,第2个getchar函数做为putchar函数的参数,将字符输出到显示设备。由此可见,第1个getchar读的是缓冲区中的奇数字符,第2个getchar读的则是偶数字符。所以这个程序只将输入偶数位的字符复制到显示设备上。下面是一个运行示例。


Welcome!ecm!  

【例20.2】下面的程序能把输入复制到输出,这个程序正确吗?


#include <stdio.h>int main( void ){      char c;      while ((c=getchar())!=EOF)             putchar(c);      printf(/"n/");      return 0;}  

程序使用一个字符变量存储getchar函数的返回值。表面看来似乎正确,其实并非如此。因为常常用getchar函数读取字符,所以被认为是字符型函数。它的原型要追述到getc函数,因为getchar是使用getc定义的宏,即


#define getchar() getc(stdin)  

而getc又是定义的宏,这里就不追究下去了。getc返回类型是整数类型,故有


int getchar(void);  

getchar函数的返回值是用户输入的第一个字符的ASCII码值,如出错则返回-1。

读字符时遇到文件结束符,函数返回一个文件结束符标志EOF,EOF在stdio.h中定义为-1。

注意:EOF是定义在头文件中的一个值。这个值不同于任何一个字符。EOF不是可输出字符,因此不能在屏幕上显示。getchar是返回整数的函数,在一般情况下确实返回的是标准输入文件中的下一个字符,但当没有输入时,返回的却是EOF。

现在把变量声明为字符型而不是整型,这就暗示可能不能接受EOF,即意味着无法接收所有可能存在的字符。这就可能存在如下三种情况。

(1)输入的某些合法字符被“截断”处理,即把低位字节赋给变量c,使c的取值与EOF相同,从而使程序在文件复制的中途停止。

(2)c不可能取得EOF这个值,程序进入死循环。

(3)由于巧合,使程序好像能够“正常”工作。这是因为有许多编译系统虽然对函数getchar的返回值进行了“截断”处理,但它们在比较表达式中并不是比较EOF和c,而是比较函数getchar的返回值与EOF。尽管这种实现并不正确,但却使程序能够“正常”运行。

由此可知,正确的程序应编写如下。


#include <stdio.h>int main( void ){     int c;     while ((c=getchar())!=EOF)           putchar(c);      printf(/"n/");     return 0;}  

EOF是为getchar函数读入文件而设计的结束符,不是从键盘输入的单字符。所以如果要结束运行,必须执行Ctrl+C。

上面程序追求简洁,下面程序是条理清楚。


#include <stdio.h>int main( void ){    while(1)    {     int c;     c=getchar();     if(c==EOF)              break;         putchar(c);     }     return 0;}  

【例20.3】为什么下面程序在有的系统中第1次编译时会给出警告信息?


#include <stdio.h>#define EOF /'0/'int main( void ){      int c;      while ((c=getchar())!=EOF)            putchar(c);      printf(/"n/");      return 0;}  

【解答】因为在该系统的stdio.h中将EOF定义为-1,这里变成重复定义。应先取消原来的定义,然后再将EOF定义为字符0,即


#undef EOF#define EOF /'0/'  

运行示范如下。


We are here!We are here!How are you?0How are you?  

如果只输入1行信息,可以定义回车结束输入,即


#undef EOF#define EOF /'n/'  

【例20.4】为什么下面程序也能正常运行?


#define EOF -1int main( void ){     register int c;     while ((c=getchar())!=EOF)          putchar(c);     printf(/"n/");     return 0;}  

【解答】getchar宏定义在stdio.h中。在没有包含头文件stdio.h时,编译器会假定getchar是一个返回类型为整型的函数。忽略警告信息继续编译即可生成可执行文件。

为了预防编程者粗心大意忘记包含头文件stdio.h,很多C语言实现在库文件中都包含有getchar函数(这也为了方便那些需要得到getchar地址的编程者)。

不过,由于忘记包含头文件stdio.h,就会在所有出现getchar宏的地方,都用getchar函数调用来替换getchar宏。因为函数调用所导致的开销增多,所以会使程序运行变慢。因为putchar的实现方法与getchar一样,所以这个分析也同样适合putchar。