格式化输入和输出
printf
用来显示格式串(format string)的内容。
printf(格式串,表达式1,表达式2….)
显示的值可以是常量,变量或者复杂的表达式。
格式串包含普通字符和转换说明(conversion specification),转换说明一字符%开头。
%后面的信息指明把数值从二进制形式转换成打印形式(字符)的方法。
%d:告诉printf把int型值从二进制形式转换成十进制数字组成的字符串。
%f:告诉printf把float型的值从二进制形式转换成十进制数字组成的字符串。
编译器不检测格式串中转换说明的数量是否和输出项的数量相符,也不检测类型是否相符。
int i=1;float x =6.0;
printf("%d %d\n",i);
printf将会正确显示变量i的值,接着显示另一个毫无意义的整数值。
printf("%d\n",i,j);
printf会显示变量i的值,但是不现实变量j的值。
printf("%f %d\n",i,x);
printf会显示出一个float型值,一个int型值,但是这两个值都没有意义。printf必须服从字符串。
转换说明给我们提供了大量输出格式的控制方法:
%m.pX
m指最小字符宽度(minimum field width)
要显示的最少字符数量。如果要显示的字符数小于m,那么值在字段内向右对齐。
%5d 将以~1234的方式显示1234,我这里暂且用~代表空格,将以1234567的形式显示1234567.
%-m.pX,-号表示左对齐。%-5d 将以1234~的方式显示1234,将以1234567的形式显示1234567.
精度p(precision)
根据转换说明符X的不同,p的含义有所不同。
- X为d,d表示十进制形式的整数。此时,p指明了待显示的数字的最少个数(少于p的话,要在数字前加上0),p的默认值是1。没有声明p时,就认为p是1.
- X为e,e表示指数形式的浮点数。此时p指明小数点后应该出现的数字的个数(默认值是6)。如果p为0,则不显示小数点和小数点后面的小数部分。
- X为f,f表示十进制形式的浮点数,没有指数。p的含义与X为e时一样。即,p指明小数点后应该出现的数字的个数(默认值是6)。如果p为0,则不显示小数点和小数点后面的小数部分。
- X为g,g表示指数形式或者是十进制式的浮点数,形式的选择根据数的大小决定。此时p指明可以显示的有效数字的最大数量。在显示大小适中的数时,说明符g采用十进制形式,在显示非常大后非常小的数时,说明符g会转换成指数形式以便减少所需的字符数。
转义序列
例如\n
使字符串包含一些特殊字符而不会使编译器引发问题。包括控制字符和对编译器有特殊含义的字符,如”。
响铃字符\a,产生一声鸣响。
回退符\b,使光标从当前位置回退一个位置。
换行符\n,光标跳到下一行的起始位置。
水平制表符\t,光标移到下一个制表符的位置
转义序列代表在显示中要执行的操作。
scanf
scanf是做什么的?
根据特定的格式读取输入。
如:
int i,j;
float x,y;
scanf("%d%d%f%f",&i,&j,&x,&y);
使用scanf的注意事项:
- 检查转换说明中的数量是否与输入的变量的数量相符。
- 检查转换说明中的变换类型是否适合输入的变量。
- 记住使用符号&。
读取数据的另一种方式是,用字符格式读取输入,然后把字符串转换成相应的数值形式。
scanf函数的本质是什么?
本质是一个模式匹配函数,试图把输入的字符组与转换说明相匹配。
scanf是如何工作的?
用自己的话通俗易懂地总结出来,解释给别人听,别人能一下听懂。
根据给定的转换说明,尝试一个一个的读取数字。如果成功读取出来指定的类型,那么继续处理下一个指定类型的数字;如果读取不出来给定格式的数字,就直接返回,剩下的输入流就不读了。
当scanf要读取一个数字,寻找一个数字的起始位置时,空格,换行符,制表符会被忽略掉,不作为识别的内容。
举例说明:
对于这样一串输入
-100-345.5-5.5e4
scanf("%d%d%f%f",&i,&j,&x,&y)会如何处理呢?
- 先处理第一个转换说明%d, 第一个非空格的字符时是;因为整数可以以-开始,scanf继续读下一个字符1,1是可以在整数内存在的,scanf继续读下一个字符0,0是可以在整数内合法存在的,继续读下一个字符,下一个字符是0,同样合法,继续读下一个字符,下一个字符是-,-不能在整数中间存在,所以scanf将读到的-100存储到i,将读到的-放回到字符流。
- 接着处理第二个转换说明%d,第一个非空格的字符是-,-在整数的开始位置,是合法的,因此继续读下一个字符3,3是合法的整数字符,继续读下一个字符4,4是合法的整数字符,继续读下一个字符5,5是合法的字符,继续读下一个字符,下一个字符是小数点.,小数点不能存在于一个整数内,因此将已经读到的-345存储到j中,将读到的小数点放回到字符流。
- 接着处理第三个转换说明%f。scanf会依次读取到.,5,和-。一个float数中不可能在数字后面出现负号,读到-后,scanf会将0.5存储到x, 把-放回字符流。
- 接着处理第四个转换说明%f.scanf依次读到-,5,.,5,e,4,和换行符。因为浮点数中不可能有换行符,所以读到换行符后,scanf将读取到的-5.5x10^4存储到y,将换行符放回字符流。换行符会 在下次调用scanf时被读取。
scanf如何识别一个整数?
先看字符是否是一个数字,正号+或负号-, 如果是,就接着读下一个字符数字,直到读到的字符不是指定类型的组成部分,比如读到了.,小数点不可能在整数中出现,此时结束对该指定类型的数字的读取,读到的不属于整数的小数点会被放回字符流中。也就是说读到不属于指定类型的字符时,该字符会被放回字符流中,等待下一次识别。
scanf如何识别一个浮点数?
先看字符是否是正号+或负号-(可出现,可不出现,有或没有都会往下读),
再接着读取一系列数字(可能包含一个小数点)
再接着读取指数部分。指数部分包括e或E,+/-(可出现也可不出现),数字。
%e、%f和%g在识别浮点数时遵循相同的规则。
如果格式串中包含普通字符,scanf会如何处理呢?
模式匹配是理解scanf处理普通字符的关键.
根据格式串中的普通字符是否为空白字符,有不同的处理。
当在格式串中遇到1个或多个连续的空白字符,scanf会持续地读空白字符直到遇到一个非空白字符为止,这个非空白字符会被放回到字符流中。格式串中空白字符的数量无关紧要(需要的话,有一个就行)。在格式串中包含空白字符,并不意味着输入中必须包含空白字符。格式串中的一个空白字符可以与输入中的任意数量的连续空白字符相匹配,包括零个。
当在格式串中遇到非空白字符的普通字符时,scanf会把它与下一个输入相比较。如果两个字符是匹配的,scanf会从字符流中丢掉这个字符,继续处理后续的格式。如果两个字符不匹配,scanf把字符放回到字符流,异常退出,不再处理格式串也不再从输入流中读取字符。
假设一个格式串“%dx%d”,调用scanf(“%dx%d”);
假设输入是“空格3x空格5”,空格就是摁了一下space空格键。
处理过程会是这样的:
在寻找第一个%d整数时, scanf忽略掉第一个空格,把%d与3匹配,把x与x匹配,在寻找下一个整数时,跳过一个空格,把%d与5相配。
假设输入是“空格3空格x空格5”,
处理过程会是这样的:
在寻找第一个%d整数时,scanf忽略掉第一个空格,把%d与3匹配,接下来在匹配X时,读到了空格,X与空格不匹配,scanf把空格放回原处,也就是把“空格x空格5”留给下一次scanf调用来读取,scanf异常退出。
scanf的最佳实践
-
除了转换说明,格式串最好不要包含其他字符。在寻找数据项时,scanf函数通常会跳过空白字符。
-
scanf格式串与printf格式串是不同的。**scanf格式串中最好不要以回车键或空格键结尾。**格式串中的回车等价于一个空格,**两者都会导致scanf函数提前进入到下一个非空白的字符。**比如,假设格式串“%d\n”,scanf会跳过空白字符,读取一个整数,然后跳到下一个非空白字符处,像这样的字符串可能会导致交互程序一直挂起,直到用户输入一个非空白字符为止。