不按回车就接受一个字符输入!

 
                                                     不按回车就接受一个字符输入!
     记得前几天的一篇日志( http://blog.csdn.net/anyue417/archive/2006/08/14/1064145.aspx)中写到,像下面这样的程序问题:
代码如下:

#include <stdio.h>

void main()
{
  int num=0,count=0;//num从键盘上得到数据,count用来记录循环次数
  for(count=0;count<5;count++)//循环5次
  {
   num=getchar();//从键盘输入数据
   printf("%c",num);
  }
}

   果然也只运行了3次,但不受什么字符不字符,整型不整型的影响,我想每次我输入一个字符完了,我要键入一个回车表示一次输入的结束,是不是输入流把回车也认为是一个字符了,然后我算了下,加上回车恰好够5次,然后我写以下代码测试:

#include <stdio.h>

void main()
{
  int num=0,count=0;//num从键盘上得到数据,count用来记录循环次数
  for(count=0;count<5;count++)//循环5次
  {
   num=getchar();//从键盘输入数据
   if(num=='/n')
   {
    count--;
    continue;
   }
   printf("%c",num);
  }
}

今天我读<<C专家编程>>的时候发现一节:

(8.6节)                      不需要按回车键就能得到一个字符

    MS-DOS程序员在转到UNIX系统之后最先提出的问题之一就是“我如何在不按一下回车键的情况下从终端读取一个字符?”在UNIX中,终端输入在缺省情况下是被“一锅端”的,也就是说整行输入是被一起处理的,这样行编辑字符(backspace , delete等)可以不通过正在运行的程序就能发挥作用。通常,这是一种人们希望的方便方法,但它也意味着在读入数据时必须按一下回车键表示输入行结束后才能得到输入的数据。这种方法对于整行整行的输入是非常有效的,但有些程序需要在每按一键之后就得到这个字符,这就有些不方便了。
这个“一次输入一个字符的”特性对于许多种类的软件来说都是非常重要的,但对于PC而言却是小菜一碟。C函数库支持这个特性,通常使用一个kbhit()的函数,如果一个字符正在等待被读取,它就会发出提示。Microsoft ,Borland 的C编译器提供了了getch()(或getche(),它可以使字符在读取的同时回显在屏幕上来)来获取单个字符,而不用等整行结束。
    人们经常感到疑惑,为什么ANSI C 不定义一个标准的函数来获取一次按键后的字符。由于没有一种标准的方法,每个系统都采用了不同的方法,这们样便使程序失去了可移植性。反对将kbhit()纳入标准的人认为:它在绝大多数情况下用于游戏软件的,而且还存在其他许多未标准化的终端I/O特性。另外,你可能并不想要一个在某些操作系统中很难实现的标准库函数。赞成它的人则认为:它在绝大多数情况下用于游戏软件,而游戏编写者并不需要很多的标准化的其它终端I/O特性。不论你支持哪个观点,事实上X3J11小组还是错过了一个使C语言成为一代学生程序员在UNIX上编写游戏的一种选择的机会(就是未吸纳这个特性)。在UNIX中,有两种方法可以实现逐个字符的输入,一种很难,一种很容易。容易的方法就是让stty程序来实现这个功能。尽管它是一种间接实现的方法,但对程序而言并无大碍。

#include<stdio.h>

main()
{
 int c;
 /*最初终端驱动处于普通的一次一行模式*/

 system("stty raw");   /*使终端驱动处于一次一字符模式*/

 c=getchar();

 system("stty cooked");   /*使终端驱动回到一次一行模式*/
}


    最后一行system("stty cooked");是必要的,因为程序结束后,终端字符驱动特性的状态将延续下去。在程序把终端设为一种滑稽的状态之后,如果不作修改,它就会始终处于这种模式。这和设置环境变量明显不同,后者在进程结束后自动消失。

    把I/O设置为raw状态可以实现阻塞式读入(blocking read),如果终端没有字符输入,进程就一直等待,直到有字符输入为止。如果需要非阻塞式读入,可以使用ioctl()(I/O控制)系统调用。它提供一个针对终端特性的良好控制层,可以告诉你在SVr4系统下是否有一个键被按下。下面的代码使用了ioctl(),这样只有当一个字符等待被读和时进程才进行读取。这种类型的I/O被称为轮询,就好像不断地询问设备状态,看看它是否有字符要传给你。

#include<sys/filio.h>
int kbhit()
{
 int i;
 ioctl(0,FIONREAD,&i);
 return i;
}

main()
{
 int i=0; 
 int c=' ';
 system("stty raw -echo");
 printf("enter 'q' to quit: /n");
 for(;c!='q';i++)
 {
  if(kbhit())
  {
   c=getchar();
   printf("/n got %c,on iteration %d",c,i);
  } 
 }
 system("stty cooked echo");
}

//

    以上内容我一一做了测试,结果就是:kbhit()这个函数应该没什么用,因为在使用kbhit()的时候并未提供输入的机会,它只检测缓冲区中有无字符,如果有键按下,则返回对应键值;否则返回零。无论有无按键都会立即返回。而这个输入怎么提供呢,反正暂时还不会用。而getch(),getche()虽说提供了输入的机会,但使系统处于“阻塞等待状态”(应该可以这么说),系统一直等待输入,别的什么也做不了,假如你想做一个先前那样的打乒乓程序,就无法实现。还有一个问题是我在标准的C语言函数库查询手册中没查到上面的三个函数 ,但我在VC6.0中可以使用它们,只不过在编译时要出警告如下:
test.c(5) : warning C4013: 'kbhit' undefined; assuming extern returning int
test.c(10) : warning C4013: 'getche' undefined; assuming extern returning int
我不懂倒底是什么原因,谁能帮忙讲解下就好了。

    后面提出的那两种方法是UNIX中的,我又不会UNIX环境编程,所以暂时不理。最后作者提到了中断,我想那其实的确是一种方法,当然更高层的实现就是多线程了。这些我现在还不会做,用中断的话须用汇编,嗯,以后再做吧。不过今天解决了上次那个getchar()要等待回车的问题,因为我在最开始的代码中用getch()代替getchar(),循环就是5次了,也算有点收获。

------------------------all above based C-------------------------

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1114543

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值