名称 | 用法 |
---|---|
putchar() | 只能输出单个字符 |
puts() | 只能输出字符串,并且输出结束后会自动换行 |
printf() | 可以输出各种类型的数据 |
对于printf()函数的格式控制符完整形式如下:
%[flag][width][.precision]type
tpye表示输出类型,比如 %d、%f、%c、%lf,type 就分别对应 d、f、c、lf;再如,%-9d中 type 对应 d。
type 这一项必须有,这意味着输出时必须要知道是什么类型。
汇总一下常见的格式控制符:
格式控制符 | 说明 |
---|---|
%c | 输出一个单一的字符 |
%hd、%d、%ld | 以十进制、有符号的形式输出 short、int、long 类型的整数 |
%hu、%u、%lu | 以十进制、无符号的形式输出 short、int、long 类型的整数 |
%ho、%o、%lo | 以八进制、不带前缀、无符号的形式输出 short、int、long 类型的整数 |
%#ho、%#o、%#lo | 以八进制、带前缀、无符号的形式输出 short、int、long 类型的整数 |
%hx、%x、%lx;%hX、%X、%lX | 以十六进制、不带前缀、无符号的形式输出 short、int、long 类型的整数。如果 x 小写,那么输出的十六进制数字也小写;如果 X 大写,那么输出的十六进制数字也大写。 |
%#hx、%#x、%#lx;%#hX、%#X、%#lX | 以十六进制、带前缀、无符号的形式输出 short、int、long 类型的整数。如果 x 小写,那么输出的十六进制数字和前缀都小写;如果 X 大写,那么输出的十六进制数字和前缀都大写。 |
%f、%lf | 以十进制的形式输出 float、double 类型的小数 |
%e、%le;%E、%lE | 以指数的形式输出 float、double 类型的小数。如果 e 小写,那么输出结果中的 e 也小写;如果 E 大写,那么输出结果中的 E 也大写。 |
%g、%lg;%G、%lG | 以十进制和指数中较短的形式输出 float、double 类型的小数,并且小数部分的最后不会添加多余的 0。如果 g 小写,那么当以指数形式输出时 e 也小写;如果 G 大写,那么当以指数形式输出时 E 也大写。 |
%s | 输出一个字符串 |
%p、%P | 以十六进制的形式输出数据的地址。P的大小写决定了十六进制前缀的大小写形式。(这里的地址都是虚拟地址,不等于数据在内存中的物理地址) |
注意:
width表示最小输出宽度,也就是至少占用几个字符的位置;
当输出结果的宽度不足 width 时,以空格补齐(如果没有指定对齐方式,默认会在左边补齐空格);当输出结果的宽度超过 width 时,width 不再起作用,按照数据本身的宽度来输出。
.precision 表示输出精度,也就是小数的位数
另外,.precision 也可以用于整数和字符串,但是功能却是相反的:
flag 是标志字符。例如,%#x中 flag 对应 #,%-9d中 flags 对应-。下表列出了 printf() 可以用的 flag:
标志字符 | 含义 |
---|---|
- | - 表示左对齐。如果没有,就按照默认的对齐方式,默认一般为右对齐 |
+ | 用于整数或者小数,表示输出符号(正负号)。如果没有,那么只有负数才会输出符号 |
空格 | 用于整数或者小数,输出值为正时冠以空格,为负时冠以负号 |
# | 对于八进制(%o)和十六进制(%x / %X)整数,# 表示在输出时添加前缀:八进制的前缀是 0,十六进制的前缀是 0x / 0X。对于小数(%f / %e / %g),# 表示强迫输出小数点。如果没有小数部分,默认是不输出小数点的,加上 # 以后,即使没有小数部分也会带上小数点 |
名称 | 用法 |
---|---|
getchar()、getche()、getch() | 这三个函数都用于输入单个字符 |
gets() | 获取一行数据,并作为字符串处理 |
scanf() | 可以输入多种类型的数据 |
函数 | 作用 | 缓冲区 | 头文件 | 回显 | 适用平台 |
---|---|---|---|---|---|
getchar() | 获取一个字符(需要回车) | 有 | stdio.h | 有 | Windows、Linux、Mac OS 等所有平台 |
getche() | 获取一个字符(无需回车) | 无 | conio.h | 有 | Windows |
getch() | 获取一个字符(无需回车) | 无 | conio.h | 无 | Windows |
get函数:获取字符串。gets() 是有缓冲区的,每次按下回车键,就代表当前输入结束了。
gets函数在新版C++中被移除了,因为不安全。可以用fgets代替,但注意fgets不会删除行末的回车字符。
gets() 和 scanf() 的主要区别是: 非常非常重要
故对于输入一串字符串,若字符串中包含有空格,则需要使用gets()函数才能正确输入。
scanf函数,格式控制符与printf函数相差无几。只是scanf没有了%p地址输出控制符号。
&称为取地址符,也就是获取变量在内存中的地址。
scanf() 控制字符串的完整写法为:
%{*} {width} type
其中,{ } 表示可有可无。各个部分的具体含义是:
匹配特定字符 %[xxx]
使用连字符 -
常用的连字符举例:
你也可以将它们合并起来,例如:
不匹配某些字符
scanf() 允许我们在%[ ]中直接指定某些不能匹配的字符,具体方法就是在不匹配的字符前面加上^。例如:
使用 scanf() 清空缓冲区的方案,就是:
scanf("%*[^\n]"); scanf("%*c");
下面我们就来解释一下。
首先需要明白的是,等到需要清空缓冲区的时候,缓冲区中的最后一个字符一定是换行符\n,因为输入缓冲区是行缓冲模式,用户按下回车键会产生换行符,结束本次输入,然后输入函数开始读取。
scanf("%*[^\n]"); 将换行符前面的所有字符清空,scanf("%*c"); 将最后剩下的换行符清空。
Scanf函数从缓冲区读取数据时的一些特性
当遇到 scanf() 函数时,程序会先检查输入缓冲区中是否有数据:
注意:
缓冲区(Buffer)又称为缓存(Cache),是内存空间的一部分。缓冲区是为了让低速的输入输出设备和高速的用户程序能够协调工作,并降低输入输出设备的读写次数。
根据不同的标准,缓冲区可以有不同的分类。
根据缓冲区对应的是输入设备还是输出设备,可以分为输入缓冲区和输出缓冲区。
根据数据刷新(也可以称为清空缓冲区,就是将缓冲区中的数据“倒出”)的时机,可以分为全缓冲、行缓冲、不带缓冲。
1)全缓冲
在这种情况下,当缓冲区被填满以后才进行真正的输入输出操作。缓冲区的大小都有限制的,比如 1KB、4MB 等,数据量达到最大值时就清空缓冲区。
在实际开发中,将数据写入文件后,打开文件并不能立即看到内容,只有清空缓冲区,或者关闭文件,或者关闭程序后,才能在文件中看到内容。这种现象,就是缓冲区在作怪。
2)行缓冲
在这种情况下,当在输入或者输出的过程中遇到换行符时,才执行真正的输入输出操作。行缓冲的典型代表就是标准输入设备(也即键盘)和标准输出设备(也即显示器)。
Linux和macOS系统中printf和scanf函数都具有行缓冲区。
3)不带缓冲
不带缓冲区,数据就没有地方缓存,必须立即进行输入输出。
getche()、getch() 就不带缓冲区,输入一个字符后立即就执行了,根本不用按下回车键。
Windows 下的 printf() 也不带缓冲区,不管最后有没有换行符\n,都会立即输出,所以对于类似的输出代码,Windows 和 Linux、Mac OS 会有不同的表现。
错误信息输出函数 perror() 也没有缓冲区。错误信息必须刻不容缓、立即、马上显示出来,缓冲区将会增加捕获错误的时间,这是毫无理由的。
总结
所谓刷新缓冲区,就是将缓冲区中的内容送达到目的地。缓冲区的刷新遵循以下的规则: