getch()函数依赖于头文件 conio.h .会在windows平台下从控制台无回显地取一个字符,并且返回读取到的字符。

然而,我在实际用这个函数才发现getch()这个函数并不简单。

getch函数从控制台读取单个字符而不回显,函数不能去读取CTRL+C,当读取一个功能键或方向键,函数必须调用两次(这就说明可以用这个函数去监控功能键和方向键),第一次调用返回0或0xe0,第二次返回实际的键代码

例如:

#include <stdio.h>
#include <conio.h>
int main()
{
while (true)
{
int tmp = _getch();
printf(" ……\n"); //测试每键入一次,打印几次
}
return 0;
}

在这个简单的小程序中,我测试了几个键盘的按键。

  • 在a~z的英文字母、数字键、以及Tab、space、ESC、Backspace、Enter等几个常用键上,printf()只会打印一次,也就是说,getch()会立即返回真实的键码值,并且被tmp变量接收。
  • 在键盘上输入上下左右的方向键,F1~F9、Delete等功能键时,printf()会打印两次。

为了探究getch()的真相,我改写了以上函数。

int main()
{
while (true)
{
int tmp = _getch();
int tmp2 = _getch();
printf(" tmp=%d\n tmp2=%d\n",tmp,tmp2);
}
return 0;
}

在键盘上依次输入上下左右得到如下键值:

  • 上     tmp=224     tmp2=72
  • 下     tmp=224     tmp2=80
  • 左     tmp=224     tmp2=75
  • 右     tmp=224     tmp2=77

上下左右方向键,getch()第一次返回 224(0xe0),第二次返回真实键值

在键盘上依次输入F1~F10、F11、F12、Delete得到如下键值:

  • F1        tmp=0    tmp2=59
  • F2        tmp=0    tmp2=60
  • F3        tmp=0    tmp2=61
  • F10      tmp=0    tmp2=68

F1~F10,getch()第一次返回 0 ,第二次返回该键的真实键值(59~68)

  • F11         tmp=224    tmp2=133
  • F12         tmp=224    tmp2=134
  • Delete     tmp=224    tmp2=83

那么问题就来了,getch()一会返回一个值,一会返回两个值,究竟要怎样写才不会出错呢?

我这里提供一种方法,仅供参考

#include <conio.h>
int main()
{
char tmp; //读取键值,或过滤功能键的第一个返回值
char tmp2; //接受功能键
while (true)
{
tmp = _getch(); if (tmp == 0 || tmp == -32)//表示读取的是功能键或者方向键,丢掉第一个返回值,读取第二个返回值
{
switch (tmp2 = _getch()) //接収功能键返回值
{
case 72://上
printf("This is ↑\n");
break;
case 59://F1
printf("This is F1\n");
break;
default:
break;
}
}
else //普通按键,如字母、数字、space,Esc等按键
{
switch (tmp)
{
case 32://空格
printf("This is Space\n");
break;
case 27://Esc
printf("This is Esc\n");
break;
default:
break;
}
} }
return 0;
}

注意1:在以上代码中 tmp 为char类型,可接受的值为 -128~127之间,所以原本 0xe0的返回值(10进制为224) 会被转换为 -32。

转换原理为 超出char范围的(即127以后的数字),把差值从 char类型的另一侧极限值重新开始计算(即-128往后排)

例如:224——> 超出97(224-127)——> -128+97-1=-32

详见char的越界赋值即其原理剖析

解决办法:

  1. 可以把tmp定义 unsigned char类型
  2. 通过计算、或者测试,得到可用的键值。

注意2:用getch()函数时,编译器可能会给出如下错误

严重性    代码    说明    项目    文件    行    禁止显示状态

错误    C4996     'getch': The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name: _getch. See online help for details.

解决办法:把getch()换成编译器要求的_getch()函数即可

getch()函数的使用方法及其返回值问题的更多相关文章

  1. 一个方法中的ajax在success中renturn一个值,但是方法的返回值是undefind?

    https://segmentfault.com/q/1010000003762379 A页面 console.log(handleData("search_list", &quo ...

  2. C#多线程函数如何传参数和返回值

          详见网站:http://WWW.MOVIH.COM就是一个多线程爬虫系统.   C#多线程函数如何传参数和返回值 提起多线程,不得不提起 委托(delegates)这个概念. 我理解的委托 ...

  3. 关于ajax中return并不能作为方法的返回值

    接下来关于ajax中的return值最后没有办法是方法的最终返回值问题 login(username,password) { console.log("进入方法"); $.ajax ...

  4. STL—— 容器(vector)数据插入insert()方法 的返回值

    vector 容器下的 insert() 方法拥有返回值,由于insert() 方法拥有4种重载函数,他的返回值不尽相同. 第一种,插入单个元素后的返回值: 1 #include <iostre ...

  5. PHP方法的返回值

    不仅是PHP,大部分编程语言的函数或者叫方法,都可以用return来定义方法的返回值.从函数这个叫法来看,本身它就是一个计算操作,因此,计算总会有个结果,如果你在方法体中处理了结果,比如进行了持久化保 ...

  6. Controller方法的返回值

    方法的返回值1.ModelAndView这个就不多说,这是最基础的,前面定义一个ModelAndView,中途使用addObject方法添加属性,再返回.视图解析器会自动扫描到的.2.String这个 ...

  7. java中Arrays类中,binarySearch()方法的返回值问题

    最近在复习Java知识,发现果然不经常使用忘得非常快... 看到binarySearch()方法的使用时,发现书上有点错误,于是就自己上机实验了一下,最后总结一下该方法的返回值. 总结:binaryS ...

  8. SSM-SpringMVC-21:SpringMVC中处理器方法之返回值Object篇

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 今天要记录的是处理方法,返回值为Object的那种,我给它分了一下类: 1.返回值为Object数值(例如1) ...

  9. Java反射机制二 获取方法的返回值或参数的泛型信息

    在使用反射机制时,我们经常需要知道方法的参数和返回值类型,很简单  ,下面上示例,示例中的两个方法非常相似 package deadLockThread; import java.lang.refle ...

随机推荐

  1. c++ cgi执行shell命令l发送qq邮件mailx

    #include <cstdlib> //随机数 #include <iostream> #include <cstdio> //popen函数调用的需要 #inc ...

  2. VS常用的快捷键

    整理代码          Ctrl+k+f 注释                 Ctrl+k+c 取消注释          Ctrl+k+u 帮助文档          F1 无调试启动     ...

  3. 分页PHP

    <?php//1.连接数据库$link = mysqli_connect('127.0.0.1','root','root','1906');//2.设置字符集mysqli_set_charse ...

  4. mysql5.7.35数据库迁移

    最近开发使用的测试环境的服务器使用的一台惠普E7300CPU\4G内存\160G西数硬盘配置,数据量近达20G!虽然作为测试数据库但也算是重要角色,一旦出现将严重影响工作.计划迁移至另一台做有RAID ...

  5. mysql全量备份与增量备份

    mysql全量备份与增量备份   1.全量备份 全量备份就是把数据库中所有的数据进行备份. 备份所有库: mysqldump -uroot -p456 -S /data/3306/mysql.sock ...

  6. Clickhouse 与 Kafka 的数据同步

    作者: LemonNan 原文地址: https://mp.weixin.qq.com/s/SUUHF9R_FKg-3vq7Q3cwBQ 注: 转载需注明作者及原文地址 介绍 Clickhouse 本 ...

  7. 使用vscode Container开发调试envoy

    由于我最近在研究 envoy 这个项目,这是个cpp的项目,对于我这种cpp新人来说还是比较有压力的,感觉处处都是坑,开个引导文章记录一下. 如果要研究 envoy 项目源码,那肯定是需要代码跳转的, ...

  8. m3u8文件合并处理

    m3u8文件合并处理 简介 M3U8 是 Unicode 版本的 M3U,用 UTF-8 编码."M3U" 和 "M3U8" 文件都是苹果公司使用的 HTTP ...

  9. Spring Boot 进行优雅的字段校验

    Controller层 VS Service层 一般推荐与业务无关的放在Controller层中进行校验,而与业务有关的放在Service层中进行校验. 那么如何将参数校验写的优雅美观呢,如果都是if ...

  10. k8s学习笔记一(搭建&部署helloworld应用)

    kubernetes 目录 kubernetes 虚拟机创建三个节点 k8s install 部署hello world 应用 issue 汇总 node 一直处理NotReady状态 重启系统后虚拟 ...