4.4.1 printf()函数
请求printf()打印变更的指令取决于变量的类型。
例如,在打印整数时使用%d说明符,而在打印字符时使用%c说明符。
这些符号被称为转换说明符(conversion specification),因为它们指定了如何把数据转换成可显示的形式。
转换说明符及作为结果的打印输出
转换说明 | 输出 |
%a | 浮点数、十六进制数字和p-记数法 |
%A | 浮点数、十六进制数字和p-记数法 |
%c | 一个字符 |
%d | 有符号十进制数 |
%e | 浮点数、指数记数法 |
%E | 浮点数、指数记数法 |
%f | 浮点数、十进制记数法 |
%g | 根据数值不同自动选择%f或%e |
%G | 根据数值不同自动选择%f或%e |
%i | 有符号十进制整数(与%d相同) |
%o | 无符号八进制整数 |
%p | 指针 |
%s | 字符串 |
%u | 无符号十进制数 |
%x | 使用十六进制数字of的无符号十六进制整数 |
%X | 使用十六进制数字OF的无符号十六进制整数 |
%% | 打印一个百分号 |
4.4.2 使用printf()
以下是printf()的使用格式
printf(control-string,item1,item2,......);
item1,item2等等都是要打印的项目,它们可以是变量、也可以是常量,甚至可以是在打印之前进行计算的表达式。
控制字符串(control-string)是一个描述项目如何打印的字符串。就是双引号内的语句。
警告:不要忘记给控制字符串后面的列表中的每个项目都使用一个转换说明。
如果您只想打印一个语句,就不需要任何转换说明;如果只想打印数据,就无须加入任何说明内容。
printf("%c%d\n",'$',2*cost);
这一句中,打印列表的第一项是一个字符常量而非变量,而第二项则是一个计算表达式。
这就说明了printf()使用的是值,无论该值是变量、常量还是表达式。
4.4.3 printf()的转换说明修饰符
可以在%和定义转换字符之间通过插入修饰符对基本的转换说明加以修改。
如果使用了一个以上的修饰符,那么它们应该与其表4.4中出现的顺序相同。并不是所有组合都是可能的。
表4.4
printf()修饰符
修饰符 | 意义 |
标志 | 五种标志(-、+、空格、#和0)都将在表4.5中描述。可以使用零个或一个标志 |
digit(s) | 字段宽度最小值。如果该字段不能容纳要打印的数或者字符串,系统就会使用更宽的字段。 |
. digit(s) | 精度。对于%e、%E和%f转换,是将要在小数点的右边打印的数字的位数;对于%g和%G,是有效数字的最大位数;%s是将要打印的字符的最大数目。对于整数,是将要打印的数字的最小位数。只使用一个.表示其后跟随一个0.%.f和%.0f相同。 |
h | 和整数转换一起使用,表示一个short int 或unsigned short int 类型数值。 |
hh | 和整数转换一起使用 ,表示一个signed char或unsigned char类型数值。 |
j | 和整数转换说明符一起使用,表示一个intmax_t或unitmax_t值。 |
l | 和整数转换一起使用,表示一个long int 或unsigned long int 类型值 |
ll | 和整数转换一起使用,表示一个long long int 或unsigned long long int 类型值 |
L | 和浮点转换一起使用,表示一个long double值 |
t | 和整数转换一起使用,表示一个prtdiff_t值(与两个指针之间的差相对应) |
z | 和整数转换一起使用,表示一个size_t值(sizeof返回的类型) |
printf()的标志
标志 | 意义 |
- | 项目左对齐的;也就是说会把项目打印在字段的左侧开始处 |
+ | 有符号的值若为正,则显示带加号的符号;若为负则带减号的符号; |
(空格) | 有符号的值若为正,则显示时带前导空格(但不显示符号);若为负则带减号符号。+标志会覆盖空格标志。 |
# | 使用转换说明的可选形式。若为%0则以0开始;若为%x或%X格式,则以0x或0X开始。对于所有的浮点形式,#保证了即使不跟任何数字也打印一个小数点;对于%g或%G格式,它防止尾随0被删除。 |
0 | 对于所有的数字格式,用前导零而不是用空格填充字段宽度。如果出现-标志或指定了精度(对于整数)则忽略该标志。 |
一、使用修饰符和标志的示例
程序清单4.7
/*width.c--字段宽度*/#include #define PAGES 931int main(){ printf("*%d*\n",PAGES); printf("*%2d*\n",PAGES); printf("*%10d*\n",PAGES); printf("*%-10d*\n",PAGES); return 0;}
输出结果如下:
*931*
*931*
* 931*
*931 * //-把字放在左端
程序清单4.8
//floats.c--一些浮点数的组合#include int main(){const double RENT=3582.99;printf("*f*\n",RENT);printf("*e*\n",RENT);printf("*4.2f*\n",RENT);printf("*3.1f*\n",RENT);printf("*10.3f*\n",RENT);printf("*10.3e*\n",RENT);printf("*+4.2f*\n",RENT);printf("*010.2f*\n",RENT);return 0;}/*输出为*3852.990000**3.852990e+03**3852.99**3853.0** 3852.990** 3.863e+03**+3852.99**0003852.99**/
程序清单4.9
/*foags.c--一些格式标志的使用示例*/#include int main(){ printf("#x %X %#x\n",31,31,31); printf("**%d**% d**% d**\n",42,42,-42); printf("**%5d**%5.3d**%05d**%05.3d**\n",6,6,6,6); //如果0标志和精度同时出现,0标志就会被忽略。return 0;}/*输出如下:1f 1F 0x1f**42** 42**-42**** 6** 006**00006** 006***/
程序清单 4.10
/*strings.c-字符串的格式化*/#include #difine BLURB "Authentic imitation! "int main(){ printf("/2s/\n",BLURB); printf("/24s/\n",BLURB); printf("/24.5s/\n",BLURB);//.5告诉printf()只打印5个字符 printf("/-24.5s/\n",BLURB);//-使文本左对齐输出 retrun 0;}/*输出如下:/Authentic imitation! // Authentic imitation!// Authe//Authe /*/
4.4.4 转换说明的意义
术语“转换”可能会带来误导,因为它可能意味着用转换后的值代替原值。转换说明实际上就是翻译说明,%d意为“把给定的值翻译成十进制整数文本表示,并打印出来。”
一、不匹配的转换
显然,应该使转换说明与要打印的值的类型匹配。
不要期望%u转换能把数字和符号分开。
二、printf()的返回值
printf()函数也有一个返回值,它返回所打印的字符的数目。
请注意计数针对所有的打印字符,包括空格和不可见的换行字符。
三、打印较长的字符
如果您必须要分割一个字符串,有三个选项可供选择。
方法1:使用多个printf()语种;
方法2:用反斜线和回车键的组合来结束一行。这就使得屏幕上的文件另起一行,并且在字符串中不会包含换行符。其效果就是在下一行中继续该字符串,不过下一行必须从行的最左边开始。如果缩进了该行,比如缩进了5个空格,那么这5个空格就会变成字符串的一部分。
方法3:采用字符串连接的方法。如果在一个用双引号引起来的字符串后面跟有另一个用双引号引起来的字符串,而且二者之间仅用空白字符分隔,那么C会把该组合当作一个字符串来处理。
在所有这些方法中,您 应该在字符串内部包含所必须的空格。
4.4.5 使用scanf()
c函数库中包含了多个输入函数,scanf()是其中最常用的一个,因为它可以读取各种格式的数据。
从键盘输入的是文件 ,因为那些键生成文本字符:字母、数字和标点。
scanf()把输入的字符串转换成各种形式:整数、浮点数、字符和C的字符串。它是printf()函数的逆操作。后者把整数、浮点数、字符和C的字符串转换成要在屏幕上显示的文本。
跟printf()一样,scanf()使用控制字符串和参数列表。控制字符串指出输入将被转换成的格式,主要区别是在参数列表中。printf()函数使用变量名、常量和表达式。而scanf()函数使用指向变量的指针。不必对指针有任何了解,只需要记住这些简单规则:
*如果使用scanf()来读取某种基本变量类型的值,请在变量名之前加上一个&。
*
如果使用scanf()
把一个字符串读进一个字符数组中,请不要使用&。
scanf()函数使用空格(换行、制表符和空格)来决定怎么把输入分成几个字段。它依次把转换说明与字段相匹配,并且跳过它们之间的空格 。惟一的例外是%c说明,即使下一个字符是空白字符,它也会读取那个字符。
scanf()函数与prinft()函数所使用的转换说明符几乎完全相同。主要的区别在于printf()把%f %e %E %g %G同时用于float类型和double类型,而scanf()只把它们用于float类型,而用于double类型时要求使用l修饰符。
一、从scanf()角度看输入
假定您使用了一个%d说明符来读取一个整数。scanf()函数开始每次读取一个输入字符,它跳过空白字符(空格、制表符和换行符)直到遇到一个非空白字符。因为它试图读取一个整数,所以scanf()期望发现一个数字字符或者一个符号(+或-)。如果它发现了一个数字或一个符号,那么它就保存之并读取下一个字符;就这样,scanf()持续读取和保存字符直到它遇到一个非数字的字符。如果遇到了一个非数字的字符,它就得出结论:它已经讲到了整数的尾部。scanf()把这个非数字字符放回输入。这就意味着程序下一次开始读取输入时,它将从前面被放弃的那个非数字字符开始。最后,scanf()计算它读取到的数字的相应数值,并将该值放到指定的变量中。
如果您使用了字段宽度,那么scanf()在字段结尾或者在第一个空白字符处(二者中最先到达的一个)终止。
如果要第一个非空白字符不是数字,比如是A而非一个数字?scanf()会停在那里,并把A(或者不管什么)放回输入。没有把任何值赋给指定变量,程序下一次读取输入时,它就在A处重新开始。ANSIC要求函数在第一个出错的地方停止读取输入。
如果使用%S说明符,那么空白字符以后的所有字符都是可以接受的,所在scanf()跳过空白字符直到遇到第一个非空白字符,然后保存再次遇到空白字符之前的所有非空白字符。 不能通过字段宽度使得scanf()用一个%S说明符读取多于一个字的输入。 最后一点,当scanf()把字符串放在一个指定的数组中时,它添加终止的'\0'使用数组内容成为一个C的字符串。 如果使用%C说明符,那么所有的输入字符都是平等的。如果下一个字符是一个空格或者换行符,将会把这个空格或换行符赋给指定的变量;不会跳过空白字符。 二、格式字符串中的常规字符 scanf()函数允许您把普通字符放在格式字符串中。除了空格字符之外的普通字符一定要与输入字符串准确匹配。 格式字符串中的空格意味着跳过下一个输入项之前的任何空格。请注意,任何空格的概念,包括没有空格的特殊情况。 除了%C以外的说明符会自动跳过输入项之前的空格。 对于%C来说,向格式字符串中添加一个空格将导致一些区别。 例如,如果在格式字符串中%C之前有一个空格,那么scanf()会跳到第一个非空白字符处。也就是说scanf("%C",&ch)会读取输入中遇到的第一个字符,而scanf(" %C",&ch)则读取遇到的第一个非空白字符。 三、scanf()的返回值 scanf()函数返回成功读入的项目的个数。 如果它没有读取任何项目,scanf()会返回值0.当它检测到“文件结尾”时,它返回EOF。 4.4.6 printf()和scanf()的*修饰符 printf()和scanf()都可以使用*修饰符来修饰说明符的意义,但是它们的方式不同。 首先看看*修饰符能为pritf()做什么。假定您不想事先把定字段宽度,而是希望由程序来指定该值,那么您可以在字段宽度部分使用*代替数字来达到目的,但是您也必须使用一个参数来告诉函数字段宽度应该是什么。也就是说,如果转换说明符是%*d,那么参数列表中应该包含一个*值和一个d值。该技术也可以和浮点值一起使用来指定精度和字段宽度。程序清单4.16 varwid.c程序
------ /*varwid.c--使用可变宽度的输出字段*/ include <stdio.h> int main(void) { unsigned width,precision; int number = 256; double weight = 242.5;printf("what field width?\n");
scanf("%d",&width); printf("The number is: %*d: \n",width,number); printf("Now enter a width and a precision: \n"); scanf("%d %d",&width,&precision); printf("weight = %*.*f\n"width,precision,weight); return 0; } 下面是一个运行示例: What field width? 6 The number is :256: Now enter a width and a precision: 8 3 weight = 242.500 Done !在scanf()中,*提供截然不同的服务。当把它放在%和说明符字母之间时,它使函数跳过相应的输入项目。
程序清单4.17 skip2.c ------ /*skip2.c--跳过输入的头两个整数*/ #include <stdio.h> int main() { int n; printf("Please enter three integers:\n"); scanf("%*d %*d %d",&n); printf("The last integer was %d\n",n); retrun 0; } 运行示例: Please enter three integers: 2004 2005 2006 The last integer was 2006 如果程序需要读取一个文件中某个特定的列,那么该功能将非常有用。4.4.7 printf()的用法提示
可以通过指定足够大的固定字段宽度使输出更加整齐清晰。 在两个转换说明符之间放一个空白字符,可以确保即使一个数字溢出了自己的字段,也不会闯入下一个数字一起输出。这是因为控制字符串中的常规字符(包括空格)会被打印出来。 如果语句中要嵌入一个数字,那么指定一个和期望的数字宽度同样小或更小的字段宽度通常会比较方便。这使得数字的宽度正合适,而无需不必要的空白符。