引入一个概念,对于计算机来说,外来数据都是输入,经过计算机处理的结果并进行显示的就是输出。在linux里面,一切都是文件,就连输入输出,都可以划归到”文件”一类,而为了管理这些文件,有个概念叫文件描述符,它们都是整数,对应着不同的文件。文件描述符0表示标准输入,文件描述符1表示标准输出,文件描述符2表示标准错误输出;标准输出和标准错误输出都对应硬件平台的屏幕,而标准输入通常对应键盘,这是最早期最简单的概念。伴随着计算机功能的强大,能处理的东西越来越多,这个概念也慢慢变得复杂模糊,以后会不会变真不清楚,就像现在的输入不单单是简单的键盘输入,就windows电脑而言,鼠标的移动、左右键的单击、u盘的插入其实都能算是输入了,而输出就是前者被电脑处理后的反应了,概念是基石,不是狭窄的通道,不要让它们限制了自我。
一、标准输入和标准输出
1.1 最早接触的scanf和printf
C标准库中针对标准输入输出的,最早接触的基本就这两个,都使用的格式字符串和参数列表且工作原理相同的两个函数。函数原型如下:
int scanf(char const *format,...);
int printf(char const *format,...);
格式化字符串中,经常遇到的就是格式转换符,统一一下:
转换符 | 说明(因为可以用于输入也可用于输出) |
---|---|
%d | 十进制整数 |
%u | 无符号整数 |
%hd | 十进制短整数 |
%ld | 十进制长整型整数 |
%x | 无符号十六进制整数 |
%o | 无符号八进制整数 |
副词# | 添加在八进制或者十六进制转换符中,可以输出进制前缀,如#o、#x |
—— | ———-我是分割线—————————– |
%c | 代表单个字符 |
%f | 浮点数,十进制计数 |
%e | 浮点数,科学计数法,小写e |
%E | 浮点数,科学技术法,大写E |
%g | 自动调整精度,根据需要判断输出十进制计数还是科学计数%e |
%G | 自动调整精度,根据需要判断输出十进制计数还是科学计数%E |
%a | 十六进制浮点数,科学计数法,小写a(如果系统支持) |
%A | 十六进制浮点数,科学计数法,大写A(如果系统支持) |
%Lf | long double型,十进制计数,要用科学计数法表示也要添加L |
—— | ————-又是分割线—————————— |
%s | 字符串 |
%p | 指针 |
%% | 一个百分号 |
上面的转换符既可用于printf输出也可用于scanf接收,但对于连续输入,还是要注意一下,不然很容易就出bug。(副词#一项不行,只可用于格式化输出)
根据目前我能找到的信息,C好像是不支持有符号整数的八进制和十六进制输出的,准确来说是不支持负数的八进制和十六进制,如果强行输出,得到的就是一个第一数位为1的二进制数转换来的非常大的一个数值,因为它以无符号来读取这个数并进行进制转换,用于输入也是同理。
printf的转换说明修饰符
上面的表格有提到一个副词#,这个其实就是转换说明修饰符之一,这些插入在%和转换符之间的符号,对转换加以修饰说明,所以称为转换说明修饰符,而在格式化输入里面不使用纯粹是为了降低复杂度,不然输入一个八进制整数,再加一个前缀’0’,本来就是一连串字符了,再来一首这个,简直是难为胖虎。
修饰符 | 说明 |
---|---|
五种标记 | #,提示输出前缀 -,输出左对齐(默认输出是右对齐的) +,确定正负添加对应+- 空格,对应正负输出空格或负号 0,确定了输出宽度的情况下,前面有空缺就用前导0补上 |
数字 | 最小字段宽度 在设置宽度不能容纳输出的数字或字符串时,系统自动调整宽度 |
.数字 | 突出顿号’.’,设置输出精度 %e转%f,表示小数点右边数字位数 对于%s,表示输出字符串中字符数 对于整型则是宽度,有必要的时候情况下用前导0补充 %.f和%.0f等同,精度为0的意思 顿号前数字表示宽度,即一共输出多少位数字,但如果和顿号后面的精度产生冲突,以精度为准 |
h | 常见于配合整型转换说明符,表示输出短整型 |
hh | 输出unsigned char类型,就是单字节无符号整型 |
ll | 常见于配合整型转换说明符,输出long long整型 |
L | 配合浮点型转换说明符,输出long double型数值 |
t | 配合整型转换说明符,输出ptrdiff_t类型值,指两指针差值的类型 |
z | 配合整型转换说明符,输出size_t类型值,sizeof返回类型值,专用于检查存储字节大小 |
上面有个有意思的转换说明修饰符–hh,为了配合输出unsigned char类型整数,实际上,char类型只是用来存储字符,它在技术本质上还是整数类型,所以对应的也就有无符号char类型了,而hh就是为这个类型准备的。其实scanf的转换说明修饰符和printf的只有些许不同,比如(#、0、.数字)不适用,而scanf的*不适用于printf。
转换其实并没有改变本质,在计算机存储中,它们还是一个个二进制数,这只是用不同的规则来翻译这段二进制数的表征意义
scanf在一板一眼的单个输入输出中很正常,当但你连续输入时往往就会有问题。
- 类型要匹配,输入时需要针对转换说明符进行输入,这个比较简单,不表
- 在格式字符串中,允许普通字符的存在,但空格以外的普通字符都必须与输入字符匹配,比如你加了个逗号在其中,你的输入也要以逗号为分隔符(有意思的是,如果你加了空格,你可以以换行符作为分割,缩进也行,其他空白符我没试过),所以一般为了不给自己找麻烦都是不添加太多花样字符
- scanf是在读取到空白的时候停止输入,所以如果你接受的输入时字符串往往只能接收到第一个单词而不是你输入的整个句子
- 读取不同类型数据的scanf使用,在读取数字需求时,scanf遇到输入缓存里面的空白(通常是换行符)就结束接收,因此这个空白就会停留在输入缓存里,而下一次的scanf是读取的字符数据,往往就会给字符串赋以换行符,所以这种情况往往要为了处理这个残留的换行符而添加getchar
总结一下,scanf和printf的工作都是转换–数值和文本之间的相互转换:从键盘输入的是文本,也就是字符串,输出到屏幕的也是字符串,而计算机本身存储的是数值。
更新中
原文地址:http://www.cnblogs.com/Jack-artical/p/16830699.html