5.10格式化I/O
1 格式化输出
执行格式化输出处理的是4个printf函数:
#include <stdio.h>
int printf(const char*restrict format, ...);
int fprintf(FILE*restrict fp, const char*restrict format, ...);
上面两个函数的返回值:成功则返回输出字符数,失败则返回负值;
int sprintf(char*restrict buf, const char*restrict format, ...);
int snprintf(char*restrict buf, size_t n, const char*restrict format, ...);
上面两个函数返回值为:成功返回存入数组的字符数,若编码出错则返回负值。
printf将格式化数据写到标准输出,fprintf写至指定的流,sprintf将格式化的字符送入数组buf中。sprintf在该数组的尾端自动加一个null字节,但该字节不包括在返回值中。
注意,sprintf函数可能会造成由buf指向的缓冲区溢出。必须要确保该缓冲区足够大。为此,引入snprintf函数。该函数中的缓冲区长度是一个显式参数,超过缓冲区尾端写的任何字符都会被丢弃。如果缓冲区足够大,snprintf函数就返回写入缓冲区的字符数。该返回值也不包含结尾的null字节。若返回值为小于缓冲区长度n的正值,那么没有截断输出。若发生编码错误,返回负值。
格式说明控制其余参数如何编写,以后又如何显式。每个参数按照转换说明编写,转换说明以字符%开始,除转换说明外,格式字符串中的其他字符将按原样,不经任何修改地被赋值输出。一个转换说明有4个可选部分,下面将他们都示于方括号中:
%[flags][fldwidth][precision][lenmodifier]convtype
其中flags为各种标志:
标志 |
说明 |
- |
在字段内左对齐输出 |
+ |
总是显示带符号转换的符号 |
空格 |
如果第一个字符不是符号,则在其前面加上一个空格 |
# |
指定另一种转换形式,例如,对16进制,加0x前缀 |
0 |
添加前导0进行填充 |
fldwidth说明转换的最小字段宽度。如果转换得到的字符较少,则用空格填充它。字段宽度是一个非负十进制数,或是一个星号。
precision说明整型转换后最少输出字位数、浮点数转换后小数点后的最少位、字符串转换后的最大字符数。精度是一个句点,后接一个可选的非负十进制整数或一个星号。
宽度和精度字段两者皆可为*。此时,一个整型参数指定宽度或精度的值。该整型参数正好位于被转换的参数之前。
lenmodifier说明参数长度,可能的取值为如下所示:
长度修饰符 |
说明 |
hh |
有符号或无符号的char |
h |
有符号或无符号的short |
l |
有符号或无符号的long或宽字符 |
ll |
有符号或无符号的long long |
j |
intmax_t或uintmat_t |
z |
size_t |
t |
ptrdiff_t |
L |
long double |
convtype是不可选的。它控制如何解释参数,如下表所示:
转换类型 |
说明 |
d |
有符号10进制整数 |
i |
有符号10进制整数 |
o |
无符号8进制整数 |
u |
无符号10进制整数 |
x |
无符号的16进制数字,并以小写abcdef表示 |
X |
无符号的16进制数字,并以大写ABCDEF表示 |
f |
浮点数 |
E/e |
用科学表示格式的浮点数 |
G/g |
使用%f和%e表示中的总的位数表示最短的来表示浮点数 G 同g格式,但表示为指数 |
c |
单个字符 |
s |
字符串 |
S |
wchar_t字符(宽字符)类型字符串 |
% |
显示百分号本身 |
p |
显示一个指针 |
n |
相连参量应是一个指针,其中存放已写字符的个数 |
下面4个函数是以上函数的变种,可变参数表(...)代换成了arg。
#include <stdio.h>
#include <stdarg.h>
int vprintf(const char*restrict format,va_list arg);
int vfprintf(FILE*restrict fp, const char*restrict format,va_list arg);
//上面两个函数的返回值:成功则返回输出字符数,失败则返回负值;
int vsprintf(char*restrict buf, const char*restrict format, va_list arg);
int vsnprintf(char*restrict buf, size_t n, const char*restrict format, va_list arg);
//上面两个函数返回值为:成功返回存入数组的字符数,若编码出错则返回负值。
2 格式化输入
执行格式化输入处理的是三个scanf函数:
#include <stdio.h>
int scanf(const char* restrict format, ...);
int fscanf(FILE*restrict fp,const char*restrict format, ...);
int sscanf(const char*restrict buf, const char*restrict format, ...);
返回值均为指定的输入项数;若输入出错或任意变换前已到达文件结尾则返回EOF;
scanf族用于分析输入字符串,并将字符串序列转换成指定类型的变量。格式之后的各参数包含了变量的地址,以用转换结果初始化这些变量。
格式说明控制如何转换参数,以便对它们赋值。转换说明以%字符开始,除转换说明和空白字符外,格式字符串中的其它字符必须与输入匹配。若有一个字符不匹配,则停止后续处理,不再读输入的其余部分。
一个转换说明有三个可选部分:
%[*][fldwidth][lenmodifier]convtype
可选的前导星号*用于抑制转换。按照转换说明的其余部分对输入进行转换,但转换结果并不存放在参数中。
fldwidth说明最大宽度(即最大字符数)。lenmodifier说明参数长度,与前述的printf取值相同。
Convtype字段类似于printf的转换类型字段,但两者之间还是有些差别的。一个差别是存储在无符号类型中的结果可在输入时带上符号。例如:-1可被转换为4294967295赋予无符号整型变量。
转换类型 |
说明 |
d |
有符号10进制整数 |
i |
有符号10进制整数 |
o |
无符号8进制整数 |
u |
无符号10进制整数 |
x |
无符号的16进制数字,并以小写abcdef表示 |
X |
无符号的16进制数字,并以大写ABCDEF表示 |
A、a、e、E、f、F、g、G |
浮点数 |
c |
单个字符 |
s |
字符串 |
S |
宽字符串 |
% |
显示百分号本身 |
p |
显示一个指针 |
n |
将到目前为止读取的字符数写入到指针所指向的无符号整数中 |
与printf族一样,scanf族也支持函数使用由<stdarg.h>说明的可变参数表。
#include <stdio.h>
#include <stdarg.h>
int vscanf(const char* restrict format, va_list arg);
int vfscanf(FILE*restrict fp,const char*restrict format, va_list arg);
int vsscanf(const char*restrict buf, const char*restrict format, va_list arg);
返回值:指定的输入项数;输入出错或在任一变换前已到达文件结尾则返回EOF。