当前位置: 首页 > news >正文

C 语言的 printf() 函数

概述

printf() 的作用: Print formatted output to the standard output stream.

printf() 的函数原型:

int printf( const char *format, argument1, argument2, ... );

printf() 函数的基本格式:

printf(格式字符串, 待打印项列表);

或者写为:

printf(格式字符串, 待打印项 1, 待打印项 2, ...);

待打印项 1, 待打印项 2 等都是要打印的项, 可以是变量, 常量或者在打印之前可以先进行求值的表达式, 然后打印这个表达式的值.

格式字符串中包含两种不同的信息:

  1. 实际要打印的字符, 即直接打印的字符, 也叫字面字符.
  2. 转换说明.

示意图 1:

示意图 2:

向 printf 或其他没有在函数原型中指明形参类型的函数传递实参时, short 类型实参被转换为 int, float 类型实参被转换为 double.

printf() 格式控制符

printf() 格式控制符的完整形式如下:

%[flag][width][.precision]type

[ ] 表示此处的内容可有可无,是可以省略的。

type 表示输出类型,即基本的转换说明,或称为转换字符。

width 表示最小输出宽度。

flag 表示标记。

precision 表示精度。

除了 type 之外统称为修饰符。

转换说明

整型

int

int 类型, 即基本整型, 通常只有十进制, 转换说明为:

%d

short int

short int 简称为 short, 即短整型. 转换说明要加前缀 h, 即:

%hd

long int

long int 简称为 long, 即长整型. 转换说明要加前缀 l, 即:

%ld

long long int

long long int 简称为 long long, 即长长整型, 是 C99 新增, C90 不支持. 转换说明要加前缀 ll, 即:

%lld

unsigned int

unsigned int 简称 unsigned, 即无符号基本整型.

有三种进制, 即十进制, 八进制, 十六进制.

以八进制和十六进制输出时, 会将符号位视为数值位, 故以八进制或十六进制形式输出整数时只能用于无符号整数.

printf() 不支持以八进制和十六进制形式输出有符号数, 也没有对应的转换说明符.

十进制:

%u

十进制没有前缀, 若加了 # 则结果未定义.

八进制:

显示前缀:%#o(得到前缀 0)
不显示前缀:%o

十六进制:

显示前缀:%#x(得到前缀 0x),%#X(得到前缀 0X)
不显示前缀:%x,%X
使用 x 则十六进制数用 1-9 和 a-f 表示.
使用 X 则十六进制数用 1-9 和 A-F 表示.

程序示例:

#include<stdio.h>
int main(void)
{unsigned int x = 100;printf("dec = %u; octal = %o; hex = %x\n", x, x, x);printf("dec = %u; octal = %o; hex = %X\n", x, x, x);printf("dec = %u; octal = %#o; hex = %#x\n", x, x, x);printf("dec = %u; octal = %#o; hex = %#X\n", x, x, x);return 0;
}

结果:

dec = 100; octal = 144; hex = 64
dec = 100; octal = 144; hex = 64
dec = 100; octal = 0144; hex = 0x64
dec = 100; octal = 0144; hex = 0X64

unsigned short int

unsigned short int 简称 unsigned short, 即无符号短整型, 分三种进制进行打印:

十进制:

%hu

八进制:

显示前缀: %#ho
不显示前缀: %ho

十六进制:

显示前缀: %#hx 或 %#hX
不显示前缀: %hx 或 %hX

unsigned long int

unsigned long int 简称为 unsigned long, 即无符号长整形.

十进制:

%lu

八进制:

显示前缀: %#lo
不显示前缀: %lo

十六进制:

显示前缀: %#lx 或 %#lX
不显示前缀: %lx 或 %lX

unsigned long long int

unsigned long long int 简称为 unsigned long long, 即无符号长长整型.

十进制:

%llu

八进制:

显示前缀: %#llo
不显示前缀: %llo

十六进制:

显示前缀: %#llx 或 %#llX
不显示前缀: %llx 或 %llX

规律:

short, long, long long 就是在 int 的 d 前面加前缀 h, l, ll.
unsigned short, unsigned long, unsigned long long 就是在 unsigned 的 u, o, x/X 前面加前缀 h, l, ll.

转换说明中的字母尽量都用小写,除了表示十六进制的 X(经测试,小写都不会出错,大写可能出错)。

此类前缀称为修饰符.

有符号类型只能以十进制输出 (虽然有符号的正数以十六进制和八进制输出也不会出错, 但只是刚好符号位为 0 而已).

无符号类型可以三种进制 (十进制, 八进制, 十六进制) 输出. 要显示八进制前缀 0 和十六进制前缀 0x 或 0X 时在转换说明的 % 后面加 #.

布尔型

转换说明:

%u

字符型

转换说明:

%c,%d,%o,%x

程序示例:

#include <stdio.h>int main(void) {char c = 'a';printf("%c\t%d\t%o\t%x\n", c, c, c, c); // a       97      141     61return 0;
}

地址

转换说明:

%p

指针之差

两个指针差值的类型为 ptrdiff_t,这是 C99 引入的类型。这是一个底层有符号整数类型。

%td

sizeof 和 strlen() 的返回值类型

这个类型为 size_t,这是 C99 引入的类型。这是一个底层无符号整数类型。

%zd

浮点型

float 和 double

十进制:

%f

指数计数法:

%e
%E

十六进制:

%a
%A

long double

十进制:

%Lf

指数计数法:

%Le

十六进制:

%La

给未在函数原型中显式说明参数类型的函数(如 printf)传递参数时,C 编译器会把 float 类型的值自动转换为 double 类型

%f, %e, %E, %Lf, %Le 都是默认小数点后输出 6 位。其中,%e, %E, %Le 都是默认小数点前输出 1 位。全部都可以四舍五入。

程序示例:

#include<stdio.h>int main(void) {float a = 123.123456789;long double b = 123.123456789L;printf("%f\n", a);printf("%e\n", a);printf("%Lf\n", a);printf("%Le\n", a);return 0;
}

执行结果:

123.123459
1.231235e+02
123.123459
1.231235e+02

程序示例:

#include <stdio.h>int main()
{float f = 3.1415926535f;double d = 3.1415926535;printf("f = %f, d = %f\n", f, d);printf("f = %.8f, d = %.8f\n", f, d);  // f 的值不再精确
}

执行结果:

f = 3.141593, d = 3.141593
f = 3.14159274, d = 3.14159265

%g

根据值的不同, 自动选择 %f 或者 %e 来打印浮点数, %e 格式用于指数小于 -4 或者大于或等于精度时.

%G

根据值的不同, 自动选择 %f 或者 %E 来打印浮点数, %e 格式用于指数小于 -4 或者大于或等于精度时.

修饰符

以上各个百分号后面的字母叫做 转换字符 . 在 转换字符百分号 之间还可以有 修饰符 . 修饰符可以修饰基本的转换说明.

转换说明即由三部分组成: 百分号, 修饰符, 转换字符 .

数字

表示宽度

转换说明中, 小数点前面的数字可以表示待打印项的最小字段宽度, 在指定宽度范围内, 内容右对齐.

如果字段宽度不能容纳待打印的内容, 系统会自动使用刚好合适的宽度.

就是%[flag][width][.precision]type当中的 width 部分.

程序示例 1:

#include<stdio.h>int main(void)
{printf("**********\n");printf("%10s\n", "hello");return 0;
}

结果:

**********hello

程序示例 2:

#include<stdio.h>int main(void)
{printf("**********\n");printf("%10d\n", 30);return 0;
}

结果:

**********30

程序示例 3:

#include<stdio.h>int main(void)
{printf("**********\n");printf("%10s\n", "hello world!");return 0;
}

结果:

**********
hello world!

表示精度

转换说明中, 小数点后面的数字还可以表示浮点数的精度, 即浮点数的小数点后面有几个数字, 可以四舍五入.

就是%[flag][width][.precision]type当中的 precision 部分.

程序示例:

#include<stdio.h>
#include<string.h>int main(void)
{float a = 1235.56789;printf("%e\n", a);    // %e, %f, %Lf 默认小数点后面 6 个数字,可以进行四舍五入printf("%.4e\n", a);  // 明确指定小数点后面 4 个数字,可以进行四舍五入printf("%.4f\n", a);  // 明确指定小数点后面 4 个数字,可以进行四舍五入return 0;
}

结果:

1.235568e+03
1.2356e+03
1235.5679

这种精度表示方式适用于 %e,%E 和 %f.

小数点前面的数字表示字段宽度, 小数点后面的数字表示输出的浮点数的小数点后面的位数.

可以看出, 这里发生了四舍五入.

如果转换说明中, 只是用了小数点, 则说明输出的数字没有小数部分, 即没有小数点以及小数点后面的数字. 也就是说 %.f%.0f 两者效果相同.

在去掉小数部分时依然会发生四舍五入.

程序示例:

#include<stdio.h>
#include<string.h>int main(void)
{float a = 12345.88888;printf("%.f\n", a); // 只有小数点printf("%.0f\n", a); return 0;
}

结果:

12346
12346

可以看出这里发生了四舍五入.

表示待打印字符的最多个数

在转换说明 %s 中, 在小数点后面加数字, 可以表示待打印的字符的最多个数.

程序示例:

#include<stdio.h>
#include<string.h>int main(void)
{char name[20] = "helloworld";printf("%s\n", name);         // 直接输出整个字符串printf("%.5s\n", name);       // 最多输出5个字符printf("********************\n");printf("%10.6s\n", name);     // 输出的字符串最多占用10个位置,最多输出6个字符,默认右对齐printf("%-10.5s\n", name);    // 输出的字符最多占用10个位置,最多输出5个字符,左对齐return 0;
}

结果:

helloworld
hello
********************hellow
hello

表示整数的最少位数

%d 转换说明中, 小数点后面有数字时, 该数字表示待输出的整数最小占用的位数, 如果指定的位数小于数字的真实位数, 则忽视这个位数的要求而直接打印数字, 如果指定的位数大于数字的真实位数, 则数字靠右打印, 左侧用数字 0 补齐要求的位数. 不论哪种情况待打印的数字都是完整输出的.

程序示例:

#include<stdio.h>
#include<string.h>int main(void)
{int a = 12345;// 最小打印四位数字,原数字超过了四位,则直接忽视这个4,打印原始的数字printf("%.4d\n", a);  // 最小打印六位数字,原数字为五位,则打印原始的数字,原始数字靠右,左侧用0补齐六位printf("%.6d\n", a);  return 0;
}

结果:

12345
012345

程序示例:

#include<stdio.h>
#include<string.h>int main(void)
{int a = 12345;printf("**********\n");printf("%10.7d\n", a);  // 指定字段宽度为 10, 至少输出 7 个数字, 不够的用 0 不足位数return 0;
}

结果:

**********0012345

标记

标记有五种: -, +, 空格, #, 0.

可以不使用或者使用多个标记.

就是%[flag][width][.precision]type当中的 flag 部分。

- 标记

- 可以使得在指定的字段范围内, 待打印项左对齐.

程序示例:

#include<stdio.h>int main(void)
{int a = 123;printf("**********\n");printf("%-10d\n", a);return 0;
}

结果:

**********
123

+ 标记

有符号值若为正, 则在前面显示 +. 若为负, 则在前面显示 -.

程序示例:

#include<stdio.h>int main(void)
{int a = 123;int b = -123;printf("%+d\n", a);printf("%+d\n", b);return 0;
}

结果:

+123
-123

空格

有符号值若为正, 则在前面显示空格, 不显示任何符号, 若为负, 则在前面显示减号.

如果在转换说明的修饰符中, 正号 + 和空格同时存在, 则正号起作用而空格不起作用.

程序示例:

#include<stdio.h>int main(void)
{int a = 123;int b = -123;printf("% d\n", a);printf("%+ d\n", a); // 正号 + 和空格同时存在, 则正号起作用而空格不起作用printf("% d\n", b);printf("%+ d\n", b); // 正号 + 和空格同时存在, 则正号起作用而空格不起作用return 0;
}

结果:

 123
+123
-123
-123

# 标记

对于 %o, 输出将以 0 开始.

对于 %x 和 %X, 输出将以 0x 和 0X 开头.

对于所有的浮点数, 即使没有小数部分也会打印一个小数点.

程序示例:

#include<stdio.h>
#include<string.h>int main(void)
{float a = 123e2;printf("%.0f\n", a);printf("%#.0f\n", a);return 0;
}

结果:

12300
12300.

对于 %g 和 %G 格式, # 防止结果后面的 0 被删除.

0 标记

对于数值格式, 用前导 0 代替空格填充字段宽度.

对于整数格式, 如果出现 - 标记或者指定最少输出的数字个数, 则忽略 0 这个标记.

程序示例 1:

#include<stdio.h>int main(void)
{int a = 88;printf("**********\n");printf("%10d\n", a);printf("%010d\n", a);  // 用前导 0 代替空格填充字段宽度printf("%-010d\n", a);  // 出现 - 标记, 标记 0 不起作用return 0;
}

结果:

**********88
0000000088
88

程序示例 2:

#include<stdio.h>int main(void)
{float a = 1.2345;printf("**********\n");printf("%10.3f\n", a);printf("%010.3f\n", a);  // 对于浮点数,指定了精度,但标记 0 依然起作用,只有整数里面的标记 0 可能被覆盖不起作用return 0;
}

结果:

**********1.235
000001.235

程序示例 3:

#include<stdio.h>int main(void)
{int a = 12345;printf("**********\n");printf("%10d\n", a);     // 指定字段宽度为10printf("%10.3d\n", a);   // 指定最少输出3位,实际为5位,因此3被忽视,直接输出原来的数字printf("%010d\n", a);    // 不指定整数最少输出的数字个数,标记 0 起作用printf("%010.3d\n", a);  // 指定整数最少输出的数字个数,标记 0 不起作用return 0;
}

结果:

**********1234512345
000001234512345

转换说明的意义

数据存储在计算机中是以二进制的数字形式存储的, 但是用 printf 将其显示在屏幕上时显示的是字符. 比如在屏幕上显示 42 是显示字符 4 和字符 2.

转化说明就负责这一转换过程. 转换说明就是一种翻译说明. 转换说明把以二进制格式存储在计算机中的值转换成一系列字符(字符串)以便于显示。转换说明是翻译说明。

%%

可以使用 %% 打印一个百分号 %

程序示例:

#include<stdio.h>
#include<string.h>
int main(void)
{printf("Only %d%% students are good.", 30);return 0;
}

结果:

Only 30% students are good.

常见错误

1.

用 %d 打印浮点数时,不会将浮点数转换为整型。

程序示例:

#include<stdio.h>
int main(void)
{float a = 10.1111115;printf("%d\n", a);return 0;
}

结果:

-1610612736

各个系统结果可能不同。

刷新输出

printf() 语句先把输出发送到一个叫做缓冲区的中间存储区域,然后缓冲区中的内容再不断地被发送到屏幕上。

C 标准明确规定了何时把缓冲区中的内容发送到屏幕:当缓冲区满,遇到换行符或者需要输入时。

从缓冲区把数据发送到屏幕或文件被称为刷新缓冲区或清空缓冲区。

C 标准明确规定了何时向屏幕发送缓冲区的内容, 即刷新缓冲区: 缓冲区满了或遇到换行符或需要输入。

缓冲区分为输入缓冲区和输出缓冲区。输入分为有缓冲输入和无缓冲输入,输出分为有缓冲输出和无缓冲输出。

如果输入的内容能立即被程序使用,则为无缓冲输入。如果输入的内容需要在刷新了缓冲区后才能被程序利用,则为有缓冲输入。C 标准为有缓冲输入

某些交互式程序要求输入必须是无缓冲的,比如打游戏。

有缓冲输入/输出分为行缓冲和块缓冲,块缓冲也叫完全缓冲。

完全缓冲是指当缓冲区被填满时才刷新缓冲区,通常出现在文件输入中。缓冲区的大小取决于系统,常见的大小为 512 字节和 4096 字节。

行缓冲是指在出现换行符时刷新缓冲区。键盘输入通常是行缓冲输入,所以在按下 Enter 键之后才刷新缓冲区。

printf 函数的返回值

returns the number of characters printed, or a negative value if an error occurs.

printf() 函数返回它打印的字符的个数.

如果输出有误, 则 printf() 返回一个负值.

程序示例:

#include<stdio.h>
int main(void)
{printf("%d\n", printf("Hello\n"));return 0;
}

结果:

Hello
6

显然, 需要求 printf("Hello\n") 表达式的返回值, 需要先计算该表达式, 效果是打印出一句话, 即 Hello.

此返回值包括了所有的字符, 尤其是空格和转义字符如 \n 等.

* 修饰符的用法

输出时可以不预先指定字段的宽度, 可以通过程序来指定.

可以用 * 修饰符来替换字段宽度.

此时需要另一个参数来告诉函数, 这个字段宽度应该是多少.

即, 如果转换说明是 %*d, 则参数列表中应该包含 *d 对应的值.

该技巧也可用于浮点值指定精度和字段宽度.

程序示例:

#include<stdio.h>
#define NUMBER 123
int main(void)
{printf("Please enter field width: ");int width = 0;scanf("%d", &width);printf("This integer is %*d\n", width, NUMBER);return 0;
}

结果:

Please enter field width: 6
This integer is    123

程序示例:

#include<stdio.h>
#define NUMBER 123.456789
int main(void)
{printf("Please enter field width: ");int width = 0;scanf("%d", &width);printf("Please enter precision: ");int precision = 0;scanf("%d", &precision);printf("This number is %*.*f.\n", width,precision,NUMBER);return 0;
}

结果:

Please enter field width: 14
Please enter precision: 3
This number is        123.457.
http://www.wxhsa.cn/company.asp?id=4335

相关文章:

  • 【GitHub每日速递 250915】3 个宝藏开源项目:超长语音合成、算法学习库、自托管软件导航,开发者速收
  • C 语言头文件
  • AFL++环境搭建
  • 晚安
  • 读人形机器人12体育领域
  • 【QT】C++基础
  • 安全研究者的MCP服务器宝典:BugBounty工具集锦
  • Unity的VisualStudio工程链接不同步、显示异常处理方法
  • Java 高性能与可维护性实战:从语言特性到工程化全链路
  • 二叉树的递归遍历
  • 我的大学成长与规划
  • 【笔记】拉格朗日插值
  • 自定义渲染管线(Unity Cocos)
  • 这是一个测试
  • 文献阅读 | Survey of Hallucination in Natural Language Generation
  • 技术 | LLaMA Factory微调记录重修版
  • 支付中心的钱包类业务应该怎么设计
  • MySQL索引浅析
  • WF 2025 游记
  • 17.时间处理
  • [MCP][02]快速入门MCP开发
  • numpy入门
  • 【simpleFOC】一个电机如何模拟不同旋钮的手感反馈?
  • 第一周作业2
  • 第一次课堂作业
  • [高可用/负载均衡] Ribbon LoadBalancer: 开源的客户端式负载均衡框架
  • 梦话周记
  • 【电机控制】无刷电机结构阐述---磁极数、槽数
  • 金刚怒目是我哭
  • nginx使用默认端口80作为服务端口