getchar使用的几个问题

今天在学习《The C Programming Language》是遇到了一个问题,就是在使用getchar()函数是遇到了不能理解的问题,书上有个例子:

#include <stdio.h>
main()
{
  int c;
  while ((c=getchar())!=EOF)
  putchar(c);
}
在GCC编译器上编译运行后,输入abc,回车后输出abc。但如果按照getchar和putchar只读入和输出一个字符的定义来看,这就出现了问题。但是细想一下,实际系统中需要考虑终端输入输出的具体实现,当读入输入流遇到回车时该行才算输入完毕,但是getchar仍然是一个一个字符的读入,赋给c,然后执行一个putchar,但是执行putchar时由于输入过程还没有完成,putchar只能将需要输出的值压到stdout中,等待输出,当输入过程完毕,此时执行由于输入输出实现的局限,被延迟的输出流,所以一下子将输出流中的数据全部输出来。

此处还要提到的是,将c定义为int类型而不是char是有原因的。在没有数据输入的时候,getchar返回一个特殊值,该值即为EOF(end of file),该值在stdio.h头文件中已经定义为-1,倘若将c定义为char,则不能存贮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并不是文件结束符,而只是相当于换行符的功能,即结束当前的输入。 

下面是一段从 The GNU C Programming Tutorial上面的解释:
getchar
If you want to read a single character from standard input, you can use the  getchar function. This function takes no parameters, but reads the next character from  stdin as an  unsigned char, and returns its value, converted to an integer. Here is a short program that uses  getchar:
#include <stdio.h>

int main()
{
  int input_character;

  printf("Hit any key, then hit RETURN.\n");
  input_character = getchar();
  printf ("The key you hit was '%c'.\n", input_character);
  printf ("Bye!\n");

  return 0;
}
Note that because  stdin is line-buffered,  getchar will not return a value until you hit the <RETURN> key. However,  getchar still only reads one character from stdin, so if you type  hellohellohello at the prompt, the program above will still only get once character. It will print the following line, and then terminate:
The key you hit was 'h'.
Bye!
 
从该段解释中可以看出,在键盘输入的情况下,getchar按照“行”进行读取,直到遇到回车键后返回,但是这些键盘的输入首先是被存进了stdin(标准输入流)的缓冲区,由getchar函数的定义可知,它只是返回一个字符,所以返回的只是第一个字符,符合函数的定义。

但有的时候在程序中使用getchar()会出现貌似该调用没有执行的假象,直接跳过了。这种情况主要还是由于stdio流的问题,由于在输入的时候总要遇到回车才能结束输入,在有的情况下回车键也被作为一个字符存入了输入流的缓冲区,然后紧接着调用getchar后,就返回了回车键,这样就相当于直接读取了一个空行,读取完毕当然返回,就导致了好像没有执行的假象。下面的代码是执行一个十六进制字符串转换为数值的代码。
#include <stdio.h>

double htoi(char s[]);
int main(void)
{   char s[100];
    int ch='Y';
    double data;
  while(ch=='Y'||ch=='y') 
    {
printf("please input the data begin with 0x or 0X,the number can be 0~9,a~f,A~F\n");
scanf("%s",s);
data=htoi(s);
if (data!=-1)
        printf("%s equals %.0f\n",s,data);
else  printf("wrong data\n");
        printf("try again (Y or y),else for quit\n");
// fflush(stdin);
ch=getchar();
if (ch=='\n')
{
          printf("ch is a return key\n"); /*scanf的最后一个回车仍然保留在输入流中,所以当getchar时直接将该回车返回了,解决办法是清空输入流*/
 ch=getchar();
 }
}
return 0;
}
最初调试时始终没有实现原来的意图,getchar没有实现原来的功能,添加了下面对ch判断是否为回车符的判断后发现最后的ch确实是回车符.
解决这个问题的方法就是在最后那个getchar调用之前先清空输入流, fflush(stdin),其实该语句并不是标准语句,但是它实现了将输入流中的数据丢弃的操作,使得后面的getchar可以等待用户输入一个字符。

从本例中我初步体会到了标准输入输出流的一点概念,积累了一定的经验。
本文大多经过本人的调试推敲,同时参考了 chinaunix上的一篇文章
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值