C语言格式化输输出
任何问题的求解都有一个重要的组成部分,那就是显示结果。下面,将深入谈论函数
printf
的格式化输出功能。这个函数将数据从道标准输出流(Standard output stream)输出。在调用这个函数的程序中应包含头文件
<stdio.h>
.
一、流
所有的输入/输出都是基于流(Stream)实现的,所谓流就是字节的序列。在输入操作中,字节从一个外部设备(如键盘、硬盘、网卡)流向主存;在输出操作中,字节从主存流向一个外部设备(如显示器、打印机、硬盘、网卡… …)。
程序开始执行时,有三个流自动的连接到程序上。通常标准输入流被连接到键盘上,标准输出流被连接到显示器上。第三个流时标准错误流(Standard error stream)被连接到显示器上。当然,操作系统也允许将这些流重定向到其他设备上。
二、printf函数实现格式化输出
printf
函数可以用来实现精确的格式化输出,每个printf函数的调用语句都包含一个描述输出格式的格式控制字符串。
格式控制字符串由转换说明符、标记、域宽、精度、和文本字符组成。这些内容与百分号(%)一起,构成了转换说明。
printf函数可以实现如下的格式化功能:
1、将浮点数的小数部分舍入到指定的十进制数位;
2、按小数点位置对齐显示一列浮点数;
3、输出数据可以左对齐和右对齐;
4、在输出的一行中的指定位置插入文本字符;
5、用指数形式表示浮点数;
6、用八进制或十六进制表示无符号整数;
7、用固定的域宽和精度来显示各种类型的数据。
printf函数的格式:printf( 格式控制字符串, 其他实参 );
其中,格式控制字符串描述了输出格式,其他实参(可选)逐个对应格式控制字符串中的每个转换说明,每个转换说明都可以一个百分号(%)作为开始、以一个转换说明符作为结束。在一个格式控制字符串中可以有多个转换说明。
- 忘记用双引号将一个格式控制字符串括起来,是一个语法错误!
打印整数
整数是一个不包含小数点的完整数,如88,0,-66。下图给出了整数的各种转换说明符,可以从中选择一种来显示整数。
转换说明符 | 说明 |
---|---|
d | 按有符号十进制整数显示 |
i | 按有符号十进制整数显示(注:在应用于scanf函数时,i和d的含义是不同的) |
o | 按无符号八进制整数显示 |
u | 按无符号十进制整数显示 |
x或X | 按无符号十六进制整数显示,x用0—f小写表示,X用0—F大写表示 |
h、l或ll | 写在任意一个整数转换说明符的前面,分别表示显示一个short型、long型、longlong型整数,它们也可称为长度修饰符 |
下面这个程序逐个使用整数转换说明来打印一个整数。
#include<stdio.h>
int main()
{
printf("%d\n", 666);
printf("%i\n", 666);
printf("%d\n", +666);
printf("%d\n", -666);
printf("%hd\n", 32000);
printf("%ld\n", 2000000000L);
printf("%o\n", 666);
printf("%u\n", 666);
printf("%u\n", -666);
printf("%x\n", 666);
printf("%X\n", 666);
}
注意:只由负号会打印出来,而整号会被舍弃,在后面会介绍如何强制打印正号。
另外,当用%u输出时,-666将被换成无符号整数4294966630,因为在把有符号数转换为无符号数时,会把符号位转换为数值位,所以在用面向无符号整数输出的转换说明符来打印一个负数时,它的数值会发生变化。
打印浮点数
浮点数都包含有一个小数点,例如88.8、0.0、或-66.66。下表介绍了各种浮点数转换说明符,可以选择一个来显示浮点数。转换说明符e和E是用指数形式来表示的,即数学中的科学计数法。例如:168.8888用科学计数法表示为1.688888 x 10^2,而计算机用指数形式表示为1.688888E+02。
在默认情况下,用转换说明符e、E和f显示的浮点数在校生点后边有六位的精度。当然,我们还可以显式地指定其他位数地精度。
转换说明符 | 说明 |
---|---|
e或E | 以指数形式显示一个浮点数 |
f或F | 以小数点固定的形式显示一个浮点数 |
g或G | 根据数据的绝对值大小,采用f浮点型式或者e或E指数形式显示一个浮点数 |
L | 放置在任意一种浮点数转换说明符前面,表示要打印的是一个长双精度型的浮点数 |
转换说明符g(或G),以e(E)或f的格式,打印不带小数部分末尾0的浮点数,如:间6.660000打印成6.66)。
若在转换成指数形式后,一个浮点数的幂值小于-4或大于等于指定的精度(默认输出六位有效数字),则采用e(E)来打印这个浮点数,否则采用f形式来打印。例如用g型式打印0.0000888、6660000.0、6.66、66.6,显示的结果分别为8.88e-05、6.66e+06、6.66、66.6。0.0000888被打印成指数形式,是因为它的幂值-5小于-4;6660000.0打印成指数是因为幂值6等于默认的精度。
浮点数转换说明符的使用演示代码:
#include<stdio.h>
int main()
{
printf("%e\n",1234567.89);
printf("%e\n",+1234567.89);
printf("%e\n",-1234567.89);
printf("%E\n",1234567.89);
printf("%f\n",1234567.89);
printf("%g\n",1234567.89);
printf("%G\n",1234567.89);
}
打印字符串或字符
转换说明符c和s分别用来打印单个字符和字符串。转换说明符c需要一个char型的实参,而转换说明符s的实参需要一个指向字符的指针。转换说明符s将使得printf函数不断地打印字符直到遇到字符串结束符(’\0’)为止。
使用演示:
#include<stdio.h>
int main()
{
char character = 'A';
printf("%c\n", character);
printf("%s\n", "This is a string.");
char string[] = "This is a string.";
printf("%s\n", string);
const char *stringPtr = "This is a string.";
printf("%s\n", stringPtr);
}
注:大多数编译器并不去检查格式控制字符串中的错误,所以可能只要到程序运行时出现了错误才意识到这样的错误
- %c打印一个字符串是错误的,%c的实参是一个char型的字符,而字符串是一个char型的指针;
- %s打印一个字符,会引起非法的数据访问,导致程序崩溃,因为%s需要的是一个char型指针;
- 双引号括起来的字符常量,在分配空间初始化时会在括起来的字符常量后面加上一个字符串结束符’\0’。
其他转换说明符
转换说明符 | 说明 |
---|---|
p | 用系统实现时所定义的方式显示一个指针的值 |
% | 显示一个百分号 |
使用示例:
#include<stdio.h>
int main()
{
int x = 888;
int *p = &x;
printf("%p\n",&x);
printf("%p\n",p);
printf("%%");
}
三、带域宽和精度的打印
数据打印区域的准确大小可以用域宽来说明,若域宽大于欲打印数据的实际数位,则数据将在指定的区域内向右对齐,代表域宽的一个整数将被插入到百分号(%)与转换说明符之间(如%4d)。
指定域宽打印整数
下面这个程序,对于域宽大于数据的实际数位,则会在指定的域宽内右对齐,若域宽小于数据的数位,实际打印域宽会增加,且负号也会占一个数据位,域宽可以与所有的转换说明符一起使用。
- 若需要左对齐可以把域宽指定为负数,当数位大于位宽时会拓宽域宽。
#include<stdio.h>
int main()
{
printf("%4d\n",6);
printf("%4d\n",66);
printf("%4d\n",666);
printf("%4d\n",6666);
printf("%4d\n\n",66666);
printf("%4d\n",-6);
printf("%4d\n",-66);
printf("%4d\n",-666);
printf("%4d\n",-6666);
printf("%4d\n\n",-66666);
}
指定精度打印整数、浮点数和字符串
printf函数允许指定精度打印数据,但对于不同的数据类型,精度的含义是不同的。
和整型转换说明符使用时,精度表示要打印的最少数位,若打印的数据的数位小于指定的精度,会在数值前补上前缀0,使得数位等于精度。
和浮点转换符e、E、f一起使用,精度表示小数点后面的数字位数。
和浮点转换符g、G使用时,精度表示打印出来的有效数字的最大位数。
和转换说明符s使用时,精度表示将要从一个字符串中打印出来的最大字符个数。
- 表示精度的方法是:在百分号和转换说明符之间,插入一个表示精度的整数,并在整数前面加上一个小数点,如%.4d、%.3f、%.8s;
#include<stdio.h>
int main(){
printf("%.4d\n%.9d\n\n", 888, 666);
double f = 123.14159;
printf("%.3f\n%.3e\n%.3g\n\n", f, f, f);
printf("%.8s\n","hello world!");
}
同时指定域宽和精度
可以同时指定域宽和精度,例如:
printf("%9.3f",123.141592);
上面这条语句将输出123.142。%9.3f
的含义:在9个数位的域宽中,以右对齐的方式,显示小数点后面3位的浮点数。
四、使用标记
printf函数还提供了一些标记来增加它的输出格式控制功能。使用标记的方法是:在紧靠%右侧写上标记,标记可以单独使用,也可以组合使用。
标记 | 说明 |
---|---|
-(减号) | 在域宽内左对齐显示输出结果 |
+(加号) | 在正数前面显示一个加号,负数前显示一个减号 |
空格 | 在没有打印加号的正数前面打印一个空格 |
# | 当使用八进制说明符o时,在输出数据前加上前缀0,十六进制说明符x或X在数据前加上前缀0x或0X;打印浮点数没有小数部分时强制显示一个小数点,对于g或G,末尾的0不会被删除 |
0(零) | 在打印的数据前加上前导0以填满域宽 |
右对齐和左对齐
#include<stdio.h>
int main(){
puts("1234567890123456789012345678901234567890");
printf("%10s%10d%10c%10f\n", "hello", 8, 'A', 6.66);
printf("%-10s%-10d%-10c%-10f\n", "hello", 8, 'A', 6.66);
}
加号标记和空格标记
#include<stdio.h>
int main(){
printf("%d %d\n",888,-888);
printf("%+d %+d\n",888,-888);
}
使用#标记
#include<stdio.h>
int main(){
int c = 66;
printf("%#o\n",c);
printf("%#x\n",c);
printf("%#X\n",c);
double f = 88.0;
printf("\n%g\n",f);
printf("%#g\n",f);
}
五、符号转义
在使用printf函数打印字符时,一些字符有特殊的含义,例如:双引号(")、反斜杠(\)等。这时候就必须使用符号转义才能打印出普通的符号。
转义符号由一个反斜杠()及其随后的特殊转义字符组成。下表说明了各种转义引发的操作:
转义序列 | 说明 |
---|---|
\’ | 输出一个单引号(’) |
\" | 输出一个双引号(") |
\? | 输出一个问好(?) |
\\ | 输出一个反斜杠() |
\a | 引发一个听得见或看得见的警告 |
\b | 光标在当前行中会退一个位置 |
\f | 光标移动到新的一个逻辑页面的开始位置 |
\n | 光标移到到新的一行的开始位置 |
\r | 光标移动到当前行的开始位置 |
\t | 光标移动到下一个水平制表符(tab)位置 |
\v | 光标移动到下一个垂直制表符(tab)位置 |