你真的懂C的格式化I/O吗?(上)

简介: 说起C语言I/O操作,学过C的人第一反应想到的肯定是printf/scanf之类的函数,那可是C语言的基础,程序调试的必备技能 :)。不错,作为一名C程序猿,printf确实是使用最为高频的函数了。但是如果我要问,如何格式化输入/输出我们想要的内容,大家可能就有点心虚了。为了修补上这个bug,今天我就和大家一起学习一下C的格式化I/O。

格式化输出


下面是ANSI C定义的标准的输出函数族:


#include <stdio.h>
printf(char *format, ...);
vprintf(const char *format, va_list arg);
sprintf(char *s, const char *format, ...);
vsprintf(char *s, const char *format, va_list arg);
fprintf(FILE *stream, const char *format, ...);
vfprintf(FILE *stream, const *format, va_list arg);
... ...


可以看到上面的函数的区别是(a:输出的目的地不同;(b:输出内容的格式不同。但是每个函数都会带有一个format参数,这个参数就是用于格式化最终输出内容的。下面以printf为例讲解一下如何通过format控制其各个参数的格式化。


printf函数通过format中定义的格式化项目,控制其对应的参数进行格式化,并将格式化之后的内容输出到标准输出设备上,其返回值为打印的字符数。


format参数包括两种类型的对象:普通字符和转换说明。在输出时,普通字符将原样输出,转换说明用于控制printf中的参数的格式化。每个转换说明都是%开始,并一个转换字符结束,比如,大家熟悉的%d,%s等,其中d和s就是转换字符。可是在% 和转换字符之间其实可以加入很多控制字符,以达到精细地控制输出格式。


下面是这些控制字符部分的定义:


控制部分:[-|+|空格|0|#][num][.][num][h|l|L]


字符 含义
- 指定被转换的参数按照左对齐的形式输出(默认是右对齐)
+ 指定在输出的数前面加上正负号
空格 如果第一个字符不是正负号,则在其前面加上一个空格
0 对于数值转换,当输出长度小于段宽度时,添加前导0进行填充
# 指定另一种输出形式。如果为o(八进制)转换,则第一个数字为0。如果为x或X,则在非0值前,加0x或0X
数字 指定最小字段宽度。转换后的参数将打印不小于最小字段宽度的字段,不足的位置用空格或0填充
小数点 用于将字段宽度和精度分开
数字 用于指定精度,即指定字符串中要打印的最大字符数,浮点数小数点后的位数、整型最少输出的数字数目
h或l或L h表示将整数作为short类型打印,字母l表示将整数作为long类型打印,字母L表示将整数作为long double类型输出


下面是转换字符部分的定义:


字符 参数类型;输出形式
d,i int类型;十进制
o int类型;无符号八进制书(没有前导0)
x,X int类型;无符号十六进制(没有前导0x或0X),10-15分别用abcdef或ABCDEF表示
u int类型;无符号十进制数
c int类型;单个字符
s char *类型;顺序打印字符串中的字符,直到遇到'\0'或已打印了由精度指定的字符数为止
f double类型;十进制小数[-]m.dddddd,d的个数由精度控制(默认值为6)
e,E double类型;[-].m.dddddde±xx或[-]m.ddddddE±xx,d的个数由精度控制(默认值为6)
g,G double类型;
p void *类型;指针(取决于具体实现)
% 不转换参数;打印一个百分号%
除了e,E和g,G一般不怎么经常使用之外,其他的字符使用频率还是很高的。


下面通过几个例子,展示一下上面转换字符和控制字符的具体用法。


  1. 示例一:以十六进制打一个整数,其他进制的整数输出类似


普通打印:


printf("0x%x\n", 1048576);
输出:0x100000


如果该整数是一个内存地址,CPU为32位,打印格式形如:0x00000001


printf("0x%.8x\n", 1048576);//.8表示整数的最小输出的数字数目为8
或者
printf("0x%08x\n", 1048576);//注意:08表示不足的位置用0填充,以保证8个字符的最小宽度。
输出:0x00100000


  1. 示例二:h或l的使用


假设系统为32bit的,int:4字节,long:4字节,long long:8字节


printf("%d\n", 4294967295U);//注意U不能省略,否则按照long型处理。4294967295:0xFFFF FFFF
输出:-1
printf("%u\n", 4294967295U);
输出:4294967295
printf("%lu\n", 4294967295UL);
输出:4294967295
printf("%lld\n", 4294967295L);
输出:4294967295
printf("%hu\n", 4294967295L);//h将4294967295L截断为65535
输出:65535


关于C语言的基本数据类型可以参考这里


  1. 示例三:字符串输出


这里说一下,字符串的精度问题,下表分别按照不同的格式打印“Hello, world”(12字符)。


printf(":%s:\n",        "Hello, world");   | :Hello, world:
printf(":%10s:\n",      "Hello, world");   | :Hello, world:
printf(":%.10s:\n",     "Hello, world");   | :Hello, wor:
printf(":%.15s:\n",     "Hello, world");   | :Hello, world:
printf(":%15s:\n",      "Hello, world");   | :   Hello, world:
printf(":%-15s:\n",     "Hello, world");   | :Hello, world   :
printf(":%15.10s:\n",   "Hello, world");   | :     Hello, wor:
printf(":%-15.10s:\n",  "Hello, world");   | :Hello, wor     :


  1. 示例四:小数输出


小数的输出主要是精度的问题,精度默认为6位。


float f = 1.0f/3;
printf("%.10f\n", f);
输出:0.3333333433


  1. 示例五:指针输出


int i  = 10;
printf("%p\n", &i);
输出:0x7ffcf9e4f270


  1. 示例六:转换说明中,宽度和精度可以用*号代替


如果宽度和精度用*代替的话,宽度和精度的值通过转换下一个参数(必须为int)来计算,比如,为了从字符串s中打印最多max个字符,可以使用下列语句:


printf("%.*s", max, s);//字符串s的打印精度由参数max确定


7.示例七:函数printf使用第一个参数判断后面参数的个数及其类型。如果参数的个数不够或者类型错误,则将得到错误的结果。注意下面两个函数调用的输出之间的区别。


printf("%shello,world!\n");//如果打印的字符串中有字符%,输出将会出错。
printf("%s\n", "%shello,world!");
输出:
hello,world!
%shello,world!


其他的输出函数,比如sprintf、fprintf等,同printf函数一样,都是按照format格式化后面的各个参数,所不同的是结果的输出位置不同,sprintf将其存在一个字符数组中,fprintf将其输出到特定的输出流中。


未完待续... ...


参考资料:《C程序设计语言》,一本每个C程序员都要精读的书,向伟大的祖师爷 Brian W.Kernighan & Dennis M.Ritchie致敬!


相关文章
|
5月前
|
存储 Windows
怎样格式化硬盘?四种硬盘格式化方法(含详细图文步骤)
这篇内容介绍了硬盘格式化的方法,包括为何要格式化硬盘(如快速清空数据、建立新分区、修复错误、改变文件系统类型)和四种格式化方式:1) 使用文件管理器,2) 通过磁盘管理器,3) 利用分区工具DiskGenius,4) 使用diskpart命令。在执行格式化前,务必备份重要数据,因为格式化会导致数据丢失。
格式化
4.3 格式化工作表 4.3.1 格式化数据 单元格及单元格区域的格式化主要包括六部分:数字、对齐、字体、边框、填充和保护。单元格或单元格区域的格式化操作必须先选择要进行格式化的单元格或单元格区域,然后通过“设置单元格格式”对话框,浮动工具栏,“开始”选项卡中“字体”组、“数字”组、“对齐方式”组、“样式”组中的相关命令或格式刷复制等几种方法来实现。 4.3.2 设置单元格的行高和列宽 1)通过拖动鼠标实现行、列 2)双击分隔线 3)通过对话框实现:"开始”选项卡,“单元格”组,单击“格式”按钮,选择“行高”或“列宽”命令 注意:可以通过选择性粘贴复制列宽,不能复制行高。 在word中双
|
10月前
硬盘分区与格式化
硬盘分区与格式化。
35 1
|
数据格式 C++ Java
notepad++如何快速格式化代码
notepad++如何快速格式化代码
15247 0
磁盘格式化
磁盘格式化
93 0
Dev格式化代码
Dev格式化代码
162 0
|
程序员 C语言
你真的懂C的格式化I/O吗?(下)
上一篇文章主要是总结了C语言下格式化输出相关的内容,这一节来总结一些格式化输入相关的内容。
103 0
|
Java API UED
格式化各种类型时间格式
功能齐全,使用方便
496 0