格式占位符 % 加上特定的数字、字母,组成格式符号。
其作用是在字符串中占位,等后面传入的参数来进行替换。
printf 函数中,字符串里如果有格式符号,可变参数列表中就得有相应的参数(变量、常量、表达式等)。
如果不提供参数,打印的结果就会出现意料外的数据(随机值)。
且格式字符匹配是按顺序的一个一个填进去。
格式化符 | 描述 |
%d | 输出 有符号 十进制 整型数字(int)(short)可以输出负数 |
%u | 输出 无符号 十进制 整型数字(unsigned int)只能输出正数 |
%ld | 输出 有符号 整型数字(long) |
%lld | 输出 有符号 整型数字(long long) |
%f | 输出 有符号 单精度浮点数字,默认为保留小数点后6位。 可指定小数点后的精度,表现方式为 %.nf ,其中 n 必须是正整数,不能为负数。n 为多少,就保留到小数点后 n 位,同时进行四舍五入。(float) |
%lf | 输出 有符号 双精度浮点数字,默认为保留小数点后6位。 可指定小数点后的精度,表现方式为 %.nlf ,其中 n 必须是正整数,不能为负数。n 为多少,就保留到小数点后 n 位,同时进行四舍五入。(double) |
%c | 在屏幕上输出一个单个的字符,对应的是 char 类型。(‘ ’) |
%s | 在屏幕上输出一连串的字符(字符串),对应的是 char * 指针类型,也即是char类型的数组。(“ ”) |
%o | 输出 有符号 8进制 整型数字(int) |
%x或&X | 输出 有符号 16进制 整型数字(int) x 如果是小写的,输出结果中的字母也全都是小写;X 是大写的,输出结果的字母也都是大写的。(a到f) |
%p | 用来向屏幕输出指针数据,即内存地址,一般是以十六进制展现的。但和 %x 不同,%p 展示的格式是特定的。一般为 8 位,右对齐,结果不足自动补 0 |
%F/f | 以浮点数输出单、双精度实数 |
%E/e | 以指数形式输出单、双精度实数 |
%g %G | %g是%f和%e的简写 %G是%F和%E的简写 |
下面先来说一下e这个字母
在c语言中有两个地方出现了e这个字母。一个是在实型数据的表示方法中,实型数据的表示方法有两种:小数形式和指数形式
在指数形式的表示中就用到了e这个字母,例如355.7它的指数形式为3.557e+2,这个有点象计算机基础知识里的科学计数法,就是355.7=3.557*10^2写成C中就是如上,e是c中指数表示形式中的阶码标志。
一个是在实数需要以指数形式输出时,输出格式说明符为%e,例如0.00567以%e格式输出就是5.670000e-003。也就是5.670000*10^-003。
也可以看成小数点的左右移动。
整型
%d 是用来输出十进制的整数,对应的数据类型是 int 。
%u 也是用来输出十进制的整数,对应的数据类型是 unsigned int。和 %d 的区别在于,%d 可以输出负数,%u 只能输出正数
表示整数的格式符号,还有 %o 和 %x,分别输出 8 进制和 16 进制的整数。
其中 %x 中的 x 如果是小写的,输出结果中的字母也全都是小写;反之,X 是大写的,输出结果的字母也都是大写的。
同样,这两种格式符号也是输出没有符号的整数结果。和 %u 一样,当给定的是一个负数参数,结果虽然不是预期的,但也是有结果。至于这个结果怎么得到的,就涉及到二进制码的反码和补码,这里就不做具体展开。
无论是 int,还是其他整型,如 short、long、long long 类型,只要数值在 int 的范围内,用%d的格式化符,也是能正常输出数值。
但如果数值大于 int 的最大范围,比如 long long 类型,就会出现意外结果。
比如在 32 位(x86)的编译器中,int 类型占 4 个字节,而 long long 类型占 8 个字节。用以上这些符号,只会识别前 4 个字节的内,后面 4 个字节的内容就会被舍弃掉,从而得出一个错误的值。
那么想要正常输出 long 或者 long long 类型的数值,就需要使用相应的格式符号。
long 类型对应的格式符号:%ld。
long long 类型对应的格式符号:%lld。
浮点型
从定义上来看,%f 是用来输出单精度浮点数 float 类型,%lf 是用来输出双精度浮点数 double 类型。
但在实际测试中,符号的使用似乎对数据的精度不会产生影响。无论是 %f 还是 %lf,都是可以输出两种类型的值。
而对精度有最直接的影响是发生在定义中。
众所周知,2 / 3 是一个无限循环小数。但在计算机中是不可能存在无限循环的概念,最后都会有一个终止的时候。
而计算到什么时候才终止,就取决于数据类型所对应的内存空间能存储多少。
正常使用 %f 和 %lf,是默认保留小数点后六位,然后输出到屏幕上。但为了方便观察不同浮点数类型的精度缺失问题,于是多扩展到小数点后 32 位。
表现方式为 %.nf 或者 %.nlf,其中 n 必须是正整数,不能为负数。n 为多少,就保留到小数点后 n 位,同时进行四舍五入。
从结果中可以发现,无论 %f 符号还是 %lf 符号,最终的输出结果对精度并没有直接的影响。
精度的影响是从变量定义开始的。
变量 a2 虽然是 double 类型的,但是后面的表达式中得出的是 float 类型的结果,而后再转变为 double 类型赋给变量 a2。从低精度向高精度类型转换,精度和数据不会缺失。所以类型转换都是从低转高。
变量 a3 的表达式虽然计算后是 double 类型,但在赋值给变量 a3 的时候进行类型转换,从高到低的类转换,精度就会发生缺失。
这里我们再看一下数据类型的
范围、精度、长度
范围:顾名思义,是数据类型可以表示的数的大小多少,如0-99这个范围内的数。
精度:是各个数据类型的位宽,也就是这个数据占几个位。如123456789,精度为9,说明宽度是9。所以也可以理解成一个数据类型的字节越大,范围就越大(范围==2^(8*字节数))其精度就越大。 数据类型只能由底类型转向高类型。
长度:是以字节表示的,一个字节是8位。所以一个字节是2的8次方,4个字节是2的32次方。
(每一位都有0,1两种可能,有多少位就是多少次方),有符号的数据类型的最高位是符号位,也就是填正负,正数最高位为0表示正数,1表示负数。所以有符号数的大小范围是2的(总位数-1)的次方,无符号数的大小范围则是2的总位数的次方。 其实一个数据类型的数字范围多少是不变的,但有符号数就负数一半,正数一半,(0占一个正数),所以其次方数要减1,(正数的次方数减完1后总数还要在减1),即除以2.而无符号数全在正数。 其精度也就是算完大小范围后看这个范围数字的最大值是多大,个十百千万等往后占几个位数,例如2^31=2147483648,那么2147483648一共10个数字也就是占了10位,则int型的精度就是10. 长度就是这个数据类型是几个字节的。
实例
整数型里的int类型
int:有符号整数,数范围为-2的31~2的31-1,其精度为10,小数位数为0,长度为4字节。
字符和字符串
%c 在屏幕上输出一个字符,对应的是 char 类型。(‘ ’)
%s 在屏幕上输出一连串的字符(字符串),对应的是 char * 指针类型,也即是char类型的数组。(“ ”)
字符这一对和上面的整型和浮点型不一样。
上面的两种类型,只要数值在范围内,同一个格式符号,输出不同类型的数据,也是能够正常显示。
但字符就不一样的,%c 对应的参数能用字符串吗?反之,%s 可以用单字符吗?
当使用 %c 格式符号,传入的参数是字符串,输出是可以输出,但得到的会是一个未知的符号。例如我运行后获得一个问号:
而使用 %s 格式符号,传入的参数是 char 类型的数据就会引发异常。
关于 %c 输入还有一个比较好玩的,有时候两个 %c,传入的参数是两个任意的整数,会构成一个新的字符,可能是汉字,或者其他字符。
指针
指针,C 新手的终点,C 高手的起点。
C 语言中很多操作都是依赖指针来进行的,而指针是直接对内存进行操作。
%p 符号中的 p 即 pointer,指针。顾名思义,该符号是用来向屏幕输出指针数据,即内存地址。
而内存地址,一般是以十六进制展现的。但和 %x 不同,%p 展示的格式是特定的。一般为 8 位,右对齐,结果不足自动补 0。
每一个内存都包含两个信息,一个是内存的地址,另一个是内存中存储的数据。
直接调用基本数据类型(如整型、浮点型、字符型、指针等),获取的是内存中存储的数据。而要调用其所对应的内存地址,就需要通过寻址运算符(&)。
例如,直接调用变量 a,输出的结果为 00000001。
直接调用指针变量 p 虽然打印的也是内存地址,但这不是它自身的地址,而是变量 a 的地址。因此,本质上还是调用了内存中所存储的数据。
数组是一连串相同类型的不同元素,如果直接调用数组变量 arr,系统不知道你需要的是数组中的哪一个数据。
因此,数组变量往往存的是数组中第一个元素的内存地址。从结果中也可以看出。
而想要获取数组中具体某一个元素的内存地址,此时已经拆分成基本的数据类型,就要通过寻址运算符来获取。