课堂

printf函数

printf 笔记

1. 基本概念

printf 是 C 标准库函数,声明在 <stdio.h> 中,用于把格式化文本输出到标准输出 stdout。

函数原型:

int printf(const char *format, ...);
  • format:格式字符串
  • ...:可变参数,数量和类型由格式字符串决定
  • 返回值:成功时返回输出的字符数;失败时返回负数
  • printf 不会自动换行,需要手动写 \n

最简示例:

#include <stdio.h>

int main(void)
{
    printf("Hello, world!\n");
    return 0;
}

2. 格式说明符

格式说明符以 % 开头,常见如下:

说明符 含义 参数类型 示例
%d / %i 有符号十进制整数 int printf("%d", 42);
%u 无符号十进制整数 unsigned int printf("%u", 42u);
%o 无符号八进制 unsigned int printf("%o", 255); → 377
%x / %X 无符号十六进制 unsigned int printf("%x", 255); → ff
%f 浮点数,默认 6 位小数 double printf("%f", 3.14);
%e / %E 科学计数法 double printf("%e", 3.14);
%g / %G 自动选择 %f 或 %e double printf("%g", 3.14);
%c 单个字符 int,通常传 char printf("%c", 'A');
%s 字符串 char * printf("%s", "hello");
%p 指针地址 void * printf("%p", (void *)&x);
%% 输出一个 % 不消耗参数 printf("%%");

注意:

  • float 传给 printf 时会自动提升为 double,所以用 %f 即可。
  • %s 要求字符串必须以 '\0' 结尾。
  • %c 的参数是 int,但传 char 通常也可以。

3. 长度修饰符

用于说明整数或浮点数的具体长度。

修饰符 配合 含义
hh d i u o x X signed char / unsigned char
h d i u o x X short / unsigned short
l d i u o x X long / unsigned long
ll d i u o x X long long / unsigned long long
z d i u o x X size_t 或对应有符号类型
j d i u o x X intmax_t / uintmax_t
t d i u o x X ptrdiff_t
L f e g long double

常见例子:

long a = 123L;
long long b = 456LL;
size_t len = strlen("hello");

printf("%ld\n", a);
printf("%lld\n", b);
printf("%zu\n", len);
printf("%Lf\n", 3.14L);

4. 标志、宽度和精度

完整格式:

%[标志][宽度][.精度][长度]说明符

常用标志

标志 作用 示例
- 左对齐 `printf("%-5d
+ 正数也显示 + printf("%+d", 5); → +5
空格 正数前显示空格 printf("% d", 5); → 5
0 用 0 填充宽度 printf("%05d", 42); → 00042
# 替代形式 printf("%#x", 255); → 0xff

宽度

宽度表示最少输出多少个字符,不够时补空格。

printf("%5d\n", 42);    // "   42"
printf("%-5d|\n", 42);  // "42   |"
printf("%05d\n", 42);   // "00042"

精度

精度以 . 开头。

  • 对整数:最少位数,不够补 0
  • 对浮点数:小数点后位数
  • 对字符串:最多输出多少个字符
printf("%.3d\n", 42);      // "042"
printf("%.2f\n", 3.14159); // "3.14"
printf("%.3s\n", "hello"); // "hel"

动态宽度和精度

用 * 从参数中读取宽度或精度。

int width = 8;
int precision = 2;

printf("%*d\n", width, 42);          // "      42"
printf("%-*d|\n", width, 42);        // "42      |"
printf("%.*f\n", precision, 3.14159); // "3.14"
printf("%*.*f\n", width, precision, 3.14159);

5. 转义字符

printf 的格式字符串中可以使用转义字符:

转义 含义
\n 换行
\t 水平制表
\r 回车
\b 退格
\f 换页
\v 垂直制表
\\ 反斜杠
\' 单引号
\" 双引号
\? 问号
\0 空字符
\ooo 八进制字符,最多三位
\xhh 十六进制字符

示例:

printf("Hello\nWorld\n");
printf("Name:\tTom\n");
printf("100%%\n");      // 输出 100%
printf("A = \x41\n");   // 输出 A = A

6. 常见用法示例

输出整数

int age = 20;
printf("Age: %d\n", age);
printf("Hex: %x\n", 255);
printf("Oct: %o\n", 255);

输出浮点数

double pi = 3.14159;
printf("%f\n", pi);      // 3.141590
printf("%.2f\n", pi);    // 3.14
printf("%8.2f\n", pi);   // "    3.14"
printf("%-8.2f|\n", pi); // "3.14    |"

输出字符和字符串

char grade = 'A';
char name[] = "Tom";

printf("%c\n", grade);
printf("%s\n", name);
printf("%.1s\n", name); // "T"

输出指针

int x = 10;
printf("%p\n", (void *)&x);

输出百分号

printf("Discount: 20%%\n");

7. printf 的返回值

printf 返回成功输出的字符数,不包括结尾的 '\0',因为 printf 不会自动添加 '\0'。

int n = printf("abc\n");
printf("%d\n", n); // 4,因为 'a'、'b'、'c'、'\n' 共 4 个字符

如果输出失败,返回负数。

8. 常见错误

格式说明符和参数类型不匹配

printf("%d\n", 3.14);   // 错误:应该用 %f
printf("%f\n", 42);     // 错误:应该用 %d
printf("%s\n", 'A');    // 错误:应该用 %c
printf("%c\n", "A");    // 错误:应该用 %s 或传 'A'

格式不匹配属于未定义行为,可能输出乱码、崩溃或看似正常但结果不可靠。

忘记换行

printf("Hello");
printf("World");

输出:

HelloWorld

应该写成:

printf("Hello\n");
printf("World\n");

字符串没有 '\0' 结尾

char s[3] = {'c', 'a', 't'};
printf("%s\n", s); // 危险,可能一直打印到内存中下一个 '\0'

应该:

char s[4] = {'c', 'a', 't', '\0'};

格式字符串漏洞

不要这样写:

printf(user_input);

如果用户输入 %s、%x 等,printf 会去栈上读取参数,可能导致崩溃或泄露信息。

应该:

printf("%s", user_input);

%n 不安全

%n 会把已输出字符数写入一个 int *,容易造成安全问题,通常不建议使用。

9. CS50 中的 printf

CS50 的 string 本质上是 char *,来自:

#include <cs50.h>

所以可以直接用 %s 打印:

#include <cs50.h>
#include <stdio.h>

int main(void)
{
    string name = get_string("Name: ");

    printf("Hello, %s\n", name);
}

输入:

Tom

输出:

Hello, Tom

10. 相关输出函数

函数 作用
printf 输出到 stdout
fprintf 输出到指定文件流
sprintf 输出到字符串,不安全
snprintf 输出到字符串,带大小限制,更安全
puts 输出字符串并自动换行
putchar 输出单个字符

示例:

fprintf(stdout, "Hello\n"); // 等价于 printf("Hello\n");

char buf[100];
snprintf(buf, sizeof(buf), "%d", 42);
puts(buf);

11. 最需要记住的写法

printf("%d\n", 42);
printf("%f\n", 3.14);
printf("%.2f\n", 3.14159);
printf("%c\n", 'A');
printf("%s\n", "hello");
printf("%5d\n", 42);
printf("%-5d|\n", 42);
printf("%05d\n", 42);
printf("%x\n", 255);
printf("%p\n", (void *)&x);
printf("%%\n");
printf("%zu\n", strlen("hello"));

12. 一句话总结

printf 按格式字符串把数据转换成文本并输出到 stdout;使用时最重要的是:格式说明符必须和参数类型匹配,并且字符串要以 '\0' 结尾。