4.2 格式输出函数printf
从计算机向外部输出设备(如显示器、打印机、磁盘等)输出信息称为“输出”。简单地说,“输出”就是将计算机内的信息以打印或存储的形式转到终端,最常用的就是将数据输出到显示器上。格式输出函数printf是C语言应用最广泛的输出函数,它将信息直接打印到屏幕上,便于程序运行者观察和调试。printf函数调用时需要包含头文件stdio.h,该头文件称为标准输入输出头文件(standard input output header)。格式为:
#include <stdio.h>
其中#与include之间不应有空格,include与<之间应有一个或多个空格。
4.2.1 标准格式输出
printf函数有多种格式输出控制,其一般形式为:
printf(“格式输出控制表列”,输出参数表列);
其中,双引号内的是格式输出控制表列,格式输出控制表列可以是直接打印在屏幕上的字符串常量,即按原样输出的普通字符,也可以是用于指定输出格式的特殊字符,即格式说明。格式说明由%和格式字符组成,如%d,%f等。在双引号后应加逗号(,),后面是输出参数表列,可以是变量,常量,表达式等,若有多个输出参数,则各参数间以逗号隔开。逗号和输出参数表列间可以没有空格,也可以有多个空格,且输出参数表列可省略,此时逗号也要一起去掉。例如:
printf("Hello world"); printf("%d", 100);
第一个输出语句仅在屏幕上打印字符串Hello world,并且没有输出参数表列。第二个输出语句中,%d称为格式输出控制,含义为整型输出,常量100为输出参数表列。该语句目的是在屏幕上打印常量100的值。
1. %d格式(或者%i)
printf函数中以%作为格式输出控制索引。%d格式(或者%i)以十进制整型格式在屏幕打印输出参数表列的值。其中,输出参数表列可以是一个参数,也可以是多个参数。输出参数的类型可以是字符型,整型,实型,指针类型等任何可转化为数值的操作对象。
范例4.1 IntegerTypePrint.c
IntegerTypePrint.c这里使用%d格式输出几种不同的输出参数,如使用%d格式输出实型数据123.456,使用%d格式输出字符型变量c的值,使用%d格式输出表达式(float)a/b的值等。(光盘\chat4\ IntegerTypePrint.c)
01 #include<stdio.h> //头文件包含stdio.h,用于调用函数printf 02 main() 03 { 04 char c=' A' ; //定义字符变量c并赋初值’A' 05 int a=1; //定义变量a并赋初值1 06 int b=2; //定义变量b并赋初值2 07 printf("c=%d, a/b=%d, b/a=%d, (float)a/b=%d\n", c, a/b, b/a, (float)a/b); 08 printf("123.456=%d\n",123.456); //%d格式输出浮点型常量123.456 09 printf("%d"); //%d格式输出无输出参数表列值(未知值) 10 }
程序第7行分别输出字符变量c的值,表达式a/b,b/a及(float)a/b的值。格式输出控制表列中所含有的非格式控制字符将原样输出,如c=,','以及(float)a/b等。'\n'表示换行符,输出表列中遇到这一符号将换行输出。
输出参数表列中字符变量c被赋值为'A',此时由于使用%d格式输出,因此输出'A'的ASCII码值65。表达式a/b,由于a和b赋初值分别为1和2,因此表达式a/b的值为0,b/a的值为2,虽然(float)a/b中对a作了强制类型转换,表达式(float)a/b的值为0.5,但以%d格式输出仍为0。
程序第8行输出浮点型常量123.456,由于C语言中将浮点型常量作为double型处理,而%d输出常量123.456在内存中的低4字节的数据,因此会输出446676599的垃圾值。
程序第9行输出无输出参数表列的数值,由于没有输出参数,系统将输出垃圾值2367460。
程序运行输出结果为:
c=65, a/b=0, b/a=2, (float)a/b=0 123.456=446676599 2367460
2. %ld格式
%ld格式用于输出long型数据对象,如定义long型变量la并赋初值12345678,则应使用%ld格式输出。例如:
long la=12345678 printf("la = %ld\n", la);
作者心得:
由于32位操作系统中int型和long型都是4字节,因此,使用%d与%ld并无本质区别。
3. %u格式
%u格式以无符号型输出数据,用于输出unsigned类型数据,使用%u格式时,系统将以无符号型输出参数表列的十进制整型值。假如参数表列的值为负数,将以该数的补码计算所得的整型十进制数输出。
范例4.2 IntegerTypeUnsigned.c
IntegerTypeUnsigned.c这里分别使用%d和%u格式输出常量-1。由于在系统中-1以补码形式存放,而%u格式将不考虑数据的符号,而直接将内存中的数值输出,因此得到与%d不一样的数值。(光盘\chat4\ IntegerTypeUnsigned.c)
01 #include<stdio.h> 02 main() 03 { 04 unsigned int a=-1; //定义unsigned int型变量a并赋初值-1 05 printf("-1=%d\n", a); //%d格式输出-1 06 printf("-1=%u\n", a); //%u格式输出-1 07 }
程序第4行将常量-1赋给unsigned int型变量a。在系统中,-1以补码形式存放。-1的补码为0xffffffff,因此变量a的值为0xffffffff。
程序第5行以%d格式输出变量a的值,由于%d格式为有符号输出,因此数值0xffffffff作为有符号数将输出-1。
程序第6行以%u格式输出,由于系统不考虑最高位符号位,因此程序将0xffffffff以十进制数输出,为4294967295。
程序运行输出结果为:
-1=-1
-1=4294967295
4. %c格式
%c格式以字符型将数据输出在屏幕上,当使用%c格式输出时,输出参数可以是字符型、整型或实型的常量或变量等。例如:
char c='a', cc='6';
printf("%c, %c, %c\n", c, cc, 122);
屏幕输出为:a, 6, z。printf函数使用%c作为格式控制,输出参数中变量c和cc分别赋初值'a'和'6'。对于输出参数122,由于其为常量,因此系统将与其对应的ASCII码表中的字符输出,为'z'。需要注意的是,使用%c格式输出时,可以使用任何能表示数值的对象作为输出参数,但此时仅取该对象在内存中的最低字节,并输出对应的字符。例如:
printf("%c, %c\n", -159, 97);
输出结果:a,a。两个不同的整型值输出了相同的字符,原因是由于%c格式仅打印输出参数在内存的最低字节值对应的字符。分析-159在内存中的存储结构,由于-159为负数,因此内存中将以补码形式存放。
[-159]原码=10000000000000000000000010011111
[-159]反码=11111111111111111111111101100000
[-159]补码=11111111111111111111111101100001
整型值97在内存中的原码、反码和补码均相同,这里仅写出其补码形式。
[97]补码 =00000000000000000000000001100001
分析两个数值的最后一个字节(低8位),均为01100001,对应数值为97,因此程序将97对应的字符'a'输出,结果为:a,a。
作者心得:
一些特殊控制字符将无法使用%c格式打印到屏幕上,如换行符\n,制表位控制符\t,退格符\b等,这些属于不可见字符,只能通过打印结果体现出来。
5. %f格式
%f格式以浮点型输出,主要用于输出float型和double型数据。默认输出小数点后6位数字,不够6位补零输出。例如:
printf("%f, %f\n", 123.456, 789);
输出结果为:123.456000, 0.000000。之所以整型常量789使用%f格式输出0.000000,是由于789的存储格式和%f的输出格式不同。整型常量789在内存中以补码形式存放,形式为:
[789]补码=00000000000000000000001100010101
默认%f以单精度浮点类型输出,并根据第2章中图2-4的格式读取内存数据。数据最高位为符号位,低23位为尾数,中间8位为指数位,因此内存中的数值构成浮点数:
0.00000000000001100010101*20
由于%f精确到小数点后7位有效数字,因此无法输出任何有效数据位,所以程序对789按%f格式将输出0.000000。
6. %e格式
%e格式以指数形式输出,指数形式由数符、数值、字符(E或e)、阶符和阶码组成,如图4-1所示。
图4-1 %e格式指数形式
其中,数符用以表示数据的正负,若数据为正,则正号(+)省略。数值部分由整数部分和小数部分组成,整数部分为1位非零的整数(即1~9之间的数),小数部分由6位数字组成,若数据小数部分多于6位,按照四舍五入处理。紧跟在数值后面的是表示指数形式的字符E或e。阶符为指数符号,分为正(+)和负(-)两种。阶码为幂指数,底数为10。%e精度与double类型一致。例如:
printf("%e, %e, %e, %e\n",123.456, 123.456789, 0.0123456789, 789);
输出结果为:1.234560e+002, -1.234568e+002, 1.234568e-001, 5.597333e-308。
7. %s格式
%s用于输出字符串。C语言中除了可以直接以普通字符形式输出字符串外,还可以将字符串放在输出表列,以%s格式输出。例如:
printf("%s\n","Hello world");
输出结果为:Hello world。除了字符串常量外,输出参数也可以是能够承载字符串的指针或者数组等变量,后续章节将对字符串输出作进一步介绍。
当字符串中含有特殊控制字符时,将执行这些特殊控制字符。例如:
printf("%s\n","Hello\nwor\0ld");
输出结果为:
Hello
wor
程序遇 '\n' 字符将执行换行操作,遇 '\0' 字符认为字符串结束,因此不会输出完整的word单词。
8. %o和%x格式
%o和%x格式分别以无符号八进制和十六进制输出数据。例如:
printf("%o, %x\n",65535,65535);
输出结果为:177777,ffff
9. %和\输出
由于%和\本身作为特殊控制符,正常情况下无法输出这类符号,需要使用特殊格式才能将其输出。操作方法为在格式控制符%或\前面重写一遍该字符。
4.2.2 格式输出控制
除了基本的格式输出控制,C语言还提供了扩展的格式输出控制。这些格式用于控制输出数据的位置、输出位数和对齐方式等。
1. %md和%-md格式
这两种格式用于按指定的宽度m以十进制整型输出数据,m为整型值。对于%md,若输出数据宽度大于m,则按照实际位数输出,若输出数据宽度小于m,则左补空格,输出总共为 m 列。对于%-md,若输出数据宽度大于 m,则按照实际位数输出,若输出数据宽度小于m,则右补空格,输出总共为m列。例如:
printf("%4d%4d%4d\n", 2, 34567, 789);
printf("%-4d%-4d%-4d\n",2,34567, 789);
输出结果如下,其中,'_'表示空格。
_ _ _2 | 34567 | _789 2_ _ _ | 34567 | 789_
2. %mc和%-mc格式
与%md和%-md格式类似,%mc和%-mc格式用于按指定宽度m输出字符数据,m为整型值。
范例4.3 SpecialTypeOutFormatChar.c
SpecialTypeOutFormatChar.c使用%mc或%-mc格式输出如下图案。
(光盘\chat4\ SpecialTypeOutFormatChar.c)
01 #include<stdio.h> 02 main() 03 { 04 printf("现在输出星型图\n"); 05 printf("%4c\n", ' *' ); //输出第一行星号 06 printf("%3c%2c\n", ' *' , ' *' ); //输出第二行星号 07 printf("%2c%4c\n", ' *' , ' *' ); //输出第三行星号 08 printf("%-6c%c\n", ' *' , ' *' ); //输出第四行星号 09 printf("%2c%4c\n", ' *' , ' *' ); //输出第五行星号 10 printf("%3c%2c\n", ' *' , ' *' ); //输出第六行星号 11 printf("%4c\n", ' *' ); //输出第七行星号 12 }
程序第5行到第11行根据每行的空格数分别使用格式输出控制不同的字符类型。程序使用格式输出%md和%-md控制空行的输出,从而使各星号的打印能够列对齐。程序输出结果为:
现在输出星型图
3. %mf、%-mf、%.nf、%m.nf及%-m.nf格式
与输出十进制整型格式类似,浮点数格式输出也可以设置输出宽度。%mf用于%-mf指定包括小数点在内的数据宽度m,当m大于实际数据宽度时,%mf左补空格,%-mf右补空格;当m小于等于实际数据宽度时,将以实际数值输出。
%.nf仅用于指定小数点后的输出宽度。当n大于数据有效位数时右边补零,当n小于数据有效位时采用四舍五入处理。例如:
printf("%.5f, %.3f\n",5.6789, 9.87654);
输出结果为:5.67890,9.877
%m.nf格式中,m用于指定包括小数点在内输出的全部数据的宽度,当m大于输出全部数据宽度时,左补空格;当m小于输出全部数据宽度时,将按实际宽度输出。n用于指定小数点后数据宽度,若n大于数据有效位宽度,右补零;若n小于等于数据有效位宽度,将采用四舍五入处理。需要注意的是,在使用这种格式输出时,将优先考虑 n 的值,即在满足 n值的基础上再判断m对数据输出的影响。当m小于等于n时,m对输出数据不起作用。例如:
printf("%6.2f, %5.3f, %8.4f\n",1.234,19.87654,100000.23);
输出结果为:_ _1.23, 19.877, 100000.2300
%-m.nf与%m.nf类似,区别在于当m的值大于输出全部数据宽度时,右补空格。
4. %ms、%-ms、%m.ns、%-m.ns及%.ns格式
%ms和%-ms用于输出宽度为m列的字符串,当m小于实际字符串长度时,将按实际字符串输出;当m大于实际字符串长度时,%m格式左补空格,%-m右补空格。
%m.ns与%-m.ns格式中,m用于指定输出字符串的长度,当m大于实际串长度时,分别左补或右补空格;当m小于等于实际字符串长度时,按实际字符串输出。n用于指定输出左边n个字符,当n大于实际字符串长度时,按实际字符串输出。需要注意的是,当m小于n时,忽略m的作用。
%.ns用于输出字符串左边n个字符,当n大于实际字符串长度时,按实际字符串输出。例如:
printf("%3s,%7.2s,%.8s,%-5.3s, %6.7s\n","china","china","china","china","china");
输出结果为:chi, _ _ _ _ _ch, china, chi_ _, _china