# 输入汇总 程序是人机交互的媒介,有输出必然也有输入,第三章我们讲解了如何将数据输出到显示器上,本章我们开始讲解如何从键盘输入数据。在C语言中,有多个函数可以从键盘获得用户输入: - scanf():和 printf() 类似,scanf() 可以输入多种类型的数据。 - getchar()、getche()、getch():这三个函数都用于输入单个字符。 - gets():获取一行数据,并作为字符串处理。 scanf() 是最灵活、最复杂、最常用的输入函数,但它不能完全取代其他函数,大家都要有所了解。 ## scanf函数 scanf 是 scan format 的缩写,意思是格式化扫描,也就是从键盘获得用户输入,和 printf 的功能正好相反。 ```c #include int main(int argc, char *argv[]){ int a = 0, b = 0, c = 0, d = 0; scanf("%d", &a); scanf("%d", &b); scanf("a+b=%d\n", a+b); scanf("%d %d", &c, &d); printf("c*d=%d\n", c*d); return 0; } ``` ## 格式控制符汇总 | 格式控制符 | 说明 | | ------------ | ------------------------------------------------------------ | | %c | 读取一个单一的字符 | | %hd、%d、%ld | 读取一个十进制整数,并分别赋值给 short、int、long 类型 | | %ho、%o、%lo | 读取一个八进制整数(可带前缀也可不带),并分别赋值给 short、int、long 类型 | | %hx、%x、%lx | 读取一个十六进制整数(可带前缀也可不带),并分别赋值给 short、int、long 类型 | | %hu、%u、%lu | 读取一个无符号整数,并分别赋值给 unsigned short、unsigned int、unsigned long 类型 | | %f、%lf | 读取一个十进制形式的小数,并分别赋值给 float、double 类型 | | %e、%le | 读取一个指数形式的小数,并分别赋值给 float、double 类型 | | %g、%lg | 既可以读取一个十进制形式的小数,也可以读取一个指数形式的小数,并分别赋值给 float、double 类型 | | %s | 读取一个字符串(以空白符为结束) | ## 输入单个字符 输入单个字符当然可以使用 scanf() 这个通用的输入函数,对应的格式控制符为`%c`,上节已经讲到了。本节我们重点讲解的是 getchar()、getche() 和 getch() 这三个专用的字符输入函数,它们具有某些 scanf() 没有的特性,是 scanf() 不能代替的。 **getchar()** 最容易理解的字符输入函数是 getchar(),它就是`scanf("%c", c)`的替代品,除了更加简洁,没有其它优势了;或者说,getchar() 就是 scanf() 的一个简化版本。 **getche()** getche() 就比较有意思了,它没有缓冲区,输入一个字符后会立即读取,不用等待用户按下回车键,这是它和 scanf()、getchar() 的最大区别。 ```c #include #include #include int main(int argc, char *argv[]) { char c = _getche(); printf("字符c:%c\n", c); system("pause"); return 0; } //ps:这里我为什么使用了_getche()函数而不是getche(),是因为我是使用VS2017的编译器是MSVC15.x的版本编译会出错,提示使用_getche()来代替getche(), 保护函数。 ``` **getch()** getch() 也没有缓冲区,输入一个字符后会立即读取,不用按下回车键,这一点和 getche() 相同。getch() 的特别之处是它没有回显,看不到输入的字符。所谓回显,就是在控制台上显示出用户输入的字符;没有回显,就不会显示用户输入的字符,就好像根本没有输入一样。 回显在大部分情况下是有必要的,它能够与用户及时交互,让用户清楚地看到自己输入的内容。但在某些特殊情况下,我们却不希望有回显,例如输入密码,有回显是非常危险的,容易被偷窥。 注意,和 getche() 一样,getch() 也位于 conio.h 头文件中,也不是标准函数,默认只能在 Windows 下使用,不能在 Linux 和 Mac OS 下使用。 ```c #include #include #include int main(int argc, char *argv[]) { char c = _getch(); printf("字符c:%c\n", c); system("pause"); return 0; } //ps: 这里的_getch()还是一样的道理,编译器处于函数名称安全保护,将getch()改为_getch() ``` 注意,和 getche() 一样,getch() 也位于 conio.h 头文件中,也不是标准函数,默认只能在 Windows 下使用,不能在 Linux 和 Mac OS 下使用。 **对三个函数的总结** | 函数 | 缓冲区 | 头文件 | 回显 | 适用平台 | | --------- | ------ | ------- | ---- | --------------------------------- | | getchar() | 有 | stdio.h | 有 | Windows、Linux、Mac OS 等所有平台 | | getche() | 无 | conio.h | 有 | Windows | | getch() | 无 | conio.h | 无 | Windows | ## 输入字符串 输入字符串当然可以使用 scanf() 这个通用的输入函数,对应的格式控制符为`%s`,除了scanf()函数,我们还可以使用gets()函数。 gets() 这个专用的字符串输入函数,它拥有一个 scanf() 不具备的特性。 ```c #include #include int main(int argc, char *argv[]) { char author[30], lang[30], url[30]; gets(author); printf("author: %s\n", author); gets(lang); printf("lang: %s\n", lang); gets(url); printf("url: %s\n", url); system("pause"); return 0; } ``` gets() 是有缓冲区的,每次按下回车键,就代表当前输入结束了,gets() 开始从缓冲区中读取内容,这一点和 scanf() 是一样的。gets() 和 scanf() 的主要区别是: - scanf() 读取字符串时以空格为分隔,遇到空格就认为当前字符串结束了,所以无法读取含有空格的字符串。 - gets() 认为空格也是字符串的一部分,只有遇到回车键时才认为字符串输入结束,所以,不管输入了多少个空格,只要不按下回车键,对 gets() 来说就是一个完整的字符串。 也就是说,gets() 能读取含有空格的字符串,而 scanf() 不能。