在C语言中, _getch函数是非缓冲读数据的,当我们按下一个键之后,程序立马就会响应,不管按下的是否为回车键。应当注意的是,_getch函数不是标准库函数,想要使用该函数,应当包含conio.h头文件。
_getch函数是不带回显的,也就是说,当我们输入了一个字符,该字符会被程序接收,但是不会在显示器中显示出来。同时,_getch函数并不从缓冲区读取字符。因为该特性,_getch函数经常用作游戏中接受用户按键的函数。
但是,在使用该函数时,发现了问题:
在Debug版本下,第一次使用_getch函数后,下一次再使用_getch函数,会自动接受一个莫名其妙的\0。但是Release版本下不会有这个情况:
(在两个版本下,都只按了一下键盘,但是区别很明显)
所以怀疑(因为并没有直接的证据证明)是:在vs环境debug版本下使用_getch函数,实际上是从缓冲区读取字符(Release和Debug版本分别从两个dll里找函数,这就使得Release版本和Debug版本的函数一般都不同),而使用_getch函数时,该函数在读取后又向缓冲区放入了一个’\0’,这就导致了在下一次使用_getch函数时,_getch函数直接从缓冲区读到了’\0’。导致看起来程序并没有在第二次使用_getch函数时等待用户输入。
解决方法:
最基础的解决方法:
因为我们已经知道了出现上文所述问题的原因(暂且认为上面的假设成立),所以我们在第一次使用_getch()后再使用一次_getch()将缓冲区的字符’\0’取出来抛掉。那么在下一次使用_getch()时缓冲区中就没有字符可以接收,程序就会停在_getch处等待用户输入。
在这里可能有读者会提出另外一个问题,为什么不使用rewind(stdin)来清理缓冲区? 本人在这里也使用rewind(stdin)测试过,但是并没有起到作用,所以我怀疑在vs的Debug版本下,_getch()函数使用的是另外的缓冲区?
进阶的解决方法:
这种方法是自己编写一个getCh函数,在要使用_getch函数时可用getCh来代替两次连续两次使用_getch函数。
在这里可能又有读者要提问了:为什么你定义的getCh函数的返回类型是int型的?
这是因为getch函数的原型就是int型的函数,在使用后返回的是用户所输入的字符对应的ASCII码值。
(_getch函数原型)
当然,要是你愿意写成char型也可以,程序在运行时会自己转换类型处理。
比较严谨的解决方法:
因为在前两种解决方法中,我们只是针对了Debug版本做出了解决方法,因为在vs的Release版本下,使用_getch函数并不会出现开篇的问题,那么如果采用了前两种解决方法写的代码,又执行了Release版本,就会导致程序在运行时,用户输入一个字符后,还需要在按任意键才会向下继续执行,就会使用户体验极差。所以才会提到这种比较严谨的解决方法。即在Release版本下没有编译条件编译里的内容,这样就不会执行其中的内容。
当然,本文只是提供了解决问题的思路,观点不一定正确,还望各位前辈斧正。
PS:本文于2018年12月8日编写。本人第一次在优快云发文,还请各位前辈多多指正。