printf 是 C 语言标准库 stdio 头文件提供的格式化输出函数,核心作用就是把不同类型的数据,按照格式字符串指定的排版规则,转换成可读文本之后输出到标准输出流,也就是控制台屏幕。之所以程序里面大量使用 printf,是因为开发调试阶段需要观察变量数值,验证运算结果,同时程序运行时也需要给用户展示提示信息,它支持整数浮点数字符字符串等多种类型自动转换,不需要开发者手动把数字转成字符。它属于可变参数函数,第一个参数是格式控制字符串,后面可以跟任意数量的参数,参数数量和类型必须和格式控制符一一对应,如果匹配错误就会出现乱码数值错乱,属于非常高频的错误点。使用的时候第一步引入 stdio.h 头文件,第二步编写格式字符串,在里面放置普通文本和格式转换占位符,第三步按照占位符顺序传入对应的变量或者常量,第四步函数执行完成会返回成功打印的字符总数,如果输出失败会返回负数 EOF。整体逻辑就是解析格式字符串,逐个识别转换符,读取后面可变参数,转换成对应字符输出到屏幕,和 fprintf 相比,printf 固定输出到 stdout,不需要额外传入文件流参数,写法更加简洁。
函数原型
int printf (const char format, ...);
参数说明
第一个参数 format 格式控制字符串,里面普通字符会原样打印,带百分号的就是格式转换占位符,用来标记后面参数的输出格式。
后面可变参数 数量类型必须和占位符匹配,可以是 int double char 指针等数据。
返回值 成功时返回本次输出的字符总个数,输出出错返回 EOF 也就是负值,这个返回值很多初学者都会忽略,做错误校验的时候可以利用这个返回值判断打印是否成功。
常用格式转换符清单
| 转换符 | 输出类型 | 说明 |
|---|---|---|
| d i | 有符号十进制整数 | 对应 int 类型 |
| u | 无符号十进制整数 | 对应 unsigned int |
| x X | 十六进制整数 | x 小写字母 X 大写字母 |
| o | 八进制整数 | 输出八进制数值 |
| f | 小数浮点数 | 对应 double 类型 |
| e E | 科学计数法浮点数 | e 小写 E 大写 |
| g G | 自动选择小数或者科学计数法 | 自动精简多余零 |
| c | 单个字符 | 输出 char 字符 |
| s | 字符串 | 输出以零结尾的字符数组 |
| p | 指针地址 | 打印指针内存地址 |
| % | 百分号本身 | 需要写两个百分号 |
格式修饰符深度讲解
格式修饰符写在百分号和转换符中间,用来控制宽度对齐小数位数补零,是 printf 进阶用法核心。
宽度控制 比如 %5d 代表这个整数至少占 5 个字符宽度,默认右对齐,如果数值本身位数超过 5 位,就按照实际位数输出不会截断。
左对齐 增加减号,比如 %-5d,代表占 5 位宽度并且左对齐,右边补空格。
补零 增加零,比如 %05d,代表宽度不足的时候前面填充零,不是填充空格。
小数精度 浮点数使用点加数字,比如 %.2f,代表保留小数点后面两位,四舍五入。
长度修饰符
% ld 对应 long 类型
% lld 对应 long long 类型
% lu 对应 unsigned long 类型
% llu 对应 unsigned long long 类型
基础示例代码
include
int main ()
{
int num = 123;
double price = 45.678;
char ch = 'A';
char str [] = "hello";
printf ("整数 % d\n", num);
printf ("浮点数 %.2f\n", price);
printf ("字符 % c\n", ch);
printf ("字符串 % s\n", str);
return 0;
}
代码里面 \n 是转义字符,代表换行,printf 里面还可以使用 \t 制表符 \r 回车 \ 反斜杠等转义字符。
深度注意事项
第一 可变参数默认提升规则,char short 传入 printf 的时候会自动提升成 int,float 会自动提升成 double,所以打印 float 也使用 % f,不需要写 % f 对应 float 专属转换符。
第二 类型不匹配属于未定义行为,比如 int 变量使用 % lld 打印,或者 double 使用 % d 打印,编译器有可能只给出警告,运行之后数值错乱,严重的时候程序崩溃。
第三 缓冲机制,stdout 默认行缓冲,遇到换行符才会刷新缓冲区,如果 printf 没有换行,并且后面程序卡住,有可能屏幕看不到打印内容,可以调用 fflush stdout 强制刷新。
第四 格式字符串安全风险,不要把外部用户输入直接当成 printf 第一个参数,如果用户输入里面自带百分号占位符,会读取栈上未知内存,产生格式化字符串漏洞,正式代码格式字符串尽量写死常量。
第五 printf 不会自动换行,每次打印之后光标停留在当前行末尾,需要手动添加 \n 实现换行效果。
printf 和 fprintf 对比
| 对比项目 | printf | fprintf |
|---|---|---|
| 输出目标 | 固定 stdout 控制台 | 自定义文件流,可以是文件 stderr |
| 第一个参数 | 格式字符串 | 文件指针加格式字符串 |
| 语法 | 更简洁 | 功能扩展版本 |
| 返回值 | 打印字符总数 | 写入字符总数 |
【常见问题】
问题 1 C 语言 printf 里面 % d 和 % ld 有什么区别
回答 1 C 语言 printf 当中 % d 用来打印 int 类型数据,% ld 用来打印 long 类型数据,如果 long 变量误用 % d,会发生类型不匹配,造成 printf 输出数值错乱,属于 printf 高频错误。
问题 2 C 语言 printf 打印之后屏幕没有显示内容是什么原因
回答 2 C 语言 printf 的 stdout 默认行缓冲,没有换行符的时候数据停留在缓冲区没有输出,可以添加 \n 换行,或者调用 fflush stdout 强制刷新缓冲区,就能看到 printf 打印结果。
问题 3 C 语言 printf 返回值代表什么含义
回答 3 C 语言 printf 返回值是本次成功输出的字符总个数,如果输出失败会返回负数 EOF,可以利用这个返回值判断 printf 打印操作是否正常完成。
问题 4 C 语言 printf 里面 %.2f 是什么作用
回答 4 C 语言 printf 里面 %.2f 是浮点数格式修饰符,作用是控制浮点数保留小数点后面两位,自动四舍五入,是 printf 格式化小数最常用写法。
【免责申明】
本文内容基于 C 语言标准库常规用法编写,不同编译器对 printf 的扩展格式符存在细微差异,代码示例仅用于学习演示,实际项目开发请结合编译环境充分测试,本文不覆盖所有极端边界场景,因为类型不匹配缓冲区溢出等代码错误造成程序异常,使用者自行承担相关风险。


