printf函数详细教程(给C++学习者的特别指南)
本文最后更新于 34 天前,其中的信息可能已经有所发展或是发生改变。

一、printf是什么?

printf是C语言的输出函数,在C++中也可以使用。它与cout相比:

  • cout:面向对象的流输出
  • printf:函数式格式化输出

简单对比

// cout方式
cout << "Hello, " << name << "! Age: " << age << endl;

// printf方式
printf("Hello, %s! Age: %d\n", name.c_str(), age);

二、printf的基本结构

2.1 基本格式

printf("格式字符串", 参数1, 参数2, ...);

示例

#include <cstdio>  // 需要这个头文件
// 或者 #include <stdio.h>

int main() {
    int age = 20;
    printf("I am %d years old.\n", age);
    return 0;
}

输出:I am 20 years old.

2.2 格式说明符

这是printf最核心的部分,告诉函数如何格式化输出:

格式符含义对应C++类型示例
%d十进制整数intprintf("%d", 123)→ 123
%f浮点数float, doubleprintf("%f", 3.14)→ 3.140000
%c单个字符charprintf("%c", 'A')→ A
%s字符串char*, stringprintf("%s", "Hello")→ Hello
%lf双精度浮点doubleprintf("%lf", 3.14)→ 3.140000

三、printf的精度控制(重点)

3.1 浮点数精度控制

#include <cstdio>

int main() {
    double num = 3.1415926535;
    
    // 基本格式:%.nf
    printf("默认: %f\n", num);        // 3.141593
    printf("0位: %.0f\n", num);       // 3
    printf("1位: %.1f\n", num);       // 3.1
    printf("2位: %.2f\n", num);       // 3.14
    printf("3位: %.3f\n", num);       // 3.142
    printf("4位: %.4f\n", num);       // 3.1416
    printf("5位: %.5f\n", num);       // 3.14159
    
    return 0;
}

注意:小数点前的.是必须的,表示精度控制。

3.2 与cout对比

#include <iostream>
#include <iomanip>
#include <cstdio>
using namespace std;

int main() {
    double num = 3.1415926535;
    
    // cout方式
    cout << "cout方式:" << endl;
    cout << fixed << setprecision(3) << num << endl;  // 3.142
    
    // printf方式
    cout << "\nprintf方式:" << endl;
    printf("%.3f\n", num);  // 3.142
    
    return 0;
}

可以看到,printf("%.3f", num)等价于 cout << fixed << setprecision(3) << num,但更简洁。


四、printf的宽度控制

4.1 基本宽度控制

#include <cstdio>

int main() {
    int num = 123;
    
    printf("无宽度: |%d|\n", num);     // |123|
    printf("宽度6: |%6d|\n", num);     // |   123|(右对齐)
    printf("宽度8: |%8d|\n", num);     // |     123|
    
    return 0;
}

4.2 左对齐

#include <cstdio>

int main() {
    int num = 123;
    
    printf("右对齐: |%6d|\n", num);    // |   123|
    printf("左对齐: |%-6d|\n", num);   // |123   |
    
    return 0;
}

记忆-表示左对齐,没有-是右对齐。

4.3 补零

#include <cstdio>

int main() {
    int num = 123;
    
    printf("普通: %6d\n", num);    //    123
    printf("补零: %06d\n", num);   // 000123
    
    double price = 12.5;
    printf("价格: $%06.2f\n", price);  // $012.50
    
    return 0;
}

五、综合示例:表格输出

5.1 用cout输出表格

#include <iostream>
#include <iomanip>
using namespace std;

int main() {
    cout << "用cout输出表格:" << endl;
    cout << left << setw(10) << "姓名" 
         << setw(8) << "年龄" 
         << setw(10) << "分数" << endl;
    cout << string(28, '-') << endl;
    
    cout << left << setw(10) << "张三" 
         << setw(8) << 20 
         << fixed << setprecision(2) << setw(10) << 95.5 << endl;
    
    cout << left << setw(10) << "李四" 
         << setw(8) << 22 
         << setw(10) << 88.75 << endl;
    
    return 0;
}

5.2 用printf输出表格(更简洁)

#include <cstdio>

int main() {
    printf("用printf输出表格:\n");
    printf("%-10s %-8s %-10s\n", "姓名", "年龄", "分数");
    printf("------------------------------\n");
    
    printf("%-10s %-8d %-10.2f\n", "张三", 20, 95.5);
    printf("%-10s %-8d %-10.2f\n", "李四", 22, 88.75);
    
    return 0;
}

两种方法输出相同的结果:

姓名        年龄      分数      
------------------------------
张三        20        95.50     
李四        22        88.75

六、特殊格式控制

6.1 输出百分号

#include <cstdio>

int main() {
    double progress = 0.756;  // 75.6%
    
    printf("进度: %.1f%%\n", progress * 100);  // 进度: 75.6%
    // 注意:%% 表示输出一个%字符
    
    return 0;
}

6.2 八进制和十六进制

#include <cstdio>

int main() {
    int num = 255;
    
    printf("十进制: %d\n", num);    // 255
    printf("八进制: %o\n", num);    // 377
    printf("十六进制(小写): %x\n", num);  // ff
    printf("十六进制(大写): %X\n", num);  // FF
    printf("带前缀: 0x%X\n", num);  // 0xFF
    
    return 0;
}

6.3 科学计数法

#include <cstdio>

int main() {
    double large_num = 1234567.89;
    
    printf("默认: %f\n", large_num);        // 1234567.890000
    printf("科学计数: %e\n", large_num);     // 1.234568e+06
    printf("科学计数: %E\n", large_num);     // 1.234568E+06
    printf("自动选择: %g\n", large_num);     // 1.23457e+06
    
    return 0;
}

七、混合类型输出

7.1 同时输出不同类型

#include <cstdio>
#include <string>
using namespace std;

int main() {
    int id = 101;
    string name = "张三";
    double score = 95.5;
    char grade = 'A';
    
    // cout方式
    // cout << "学号:" << id << " 姓名:" << name 
    //      << " 分数:" << score << " 等级:" << grade << endl;
    
    // printf方式
    printf("学号:%d 姓名:%s 分数:%.1f 等级:%c\n", 
           id, name.c_str(), score, grade);
    
    return 0;
}

注意:printf输出string时需要用.c_str()转换为C风格字符串。

7.2 复杂的格式化

#include <cstdio>

int main() {
    printf("商品价格表:\n");
    printf("========================\n");
    printf("%-15s %8s %10s\n", "商品名", "单价", "小计");
    printf("------------------------\n");
    
    printf("%-15s %8.2f %10.2f\n", "苹果", 5.99, 5.99 * 3);
    printf("%-15s %8.2f %10.2f\n", "香蕉", 3.50, 3.50 * 2);
    printf("%-15s %8.2f %10.2f\n", "橙子", 4.25, 4.25 * 5);
    printf("------------------------\n");
    printf("%-15s %18.2f\n", "总计", 5.99 * 3 + 3.50 * 2 + 4.25 * 5);
    
    return 0;
}

输出:

商品价格表:
========================
商品名               单价        小计
------------------------
苹果                5.99      17.97
香蕉                3.50       7.00
橙子                4.25      21.25
------------------------
总计                         46.22

八、常见错误与注意事项

8.1 类型不匹配

// 错误示例
int age = 20;
printf("Age: %f\n", age);  // 错误!应该用%d而不是%f

// 正确
printf("Age: %d\n", age);

8.2 忘记字符串转换

#include <string>
using namespace std;

// 错误示例
string name = "Tom";
printf("Hello, %s\n", name);  // 错误!需要.c_str()

// 正确
printf("Hello, %s\n", name.c_str());

8.3 参数个数不匹配

// 错误:少了参数
printf("Name: %s, Age: %d\n", "Tom");  // 缺少age参数

// 错误:多了参数
printf("Name: %s\n", "Tom", 20);  // 20没用到

8.4 转义字符

printf("第一行\n第二行\n");  // \n 换行
printf("制表符:\t内容\n");    // \t 制表符
printf("引号:\"Hello\"\n");   // \" 输出引号
printf("反斜杠:\\n\n");       // \\ 输出反斜杠

九、与cout的详细对比

9.1 简单对比

#include <iostream>
#include <iomanip>
#include <cstdio>
using namespace std;

int main() {
    int a = 10;
    double b = 3.14159;
    string c = "test";
    
    // cout
    cout << "a=" << a << ", b=" << fixed << setprecision(3) 
         << b << ", c=" << c << endl;
    
    // printf
    printf("a=%d, b=%.3f, c=%s\n", a, b, c.c_str());
    
    return 0;
}

9.2 性能对比

#include <iostream>
#include <cstdio>
#include <chrono>
using namespace std;
using namespace chrono;

int main() {
    int n = 100000;
    
    // 测试cout
    auto start1 = high_resolution_clock::now();
    for (int i = 0; i < n; i++) {
        cout << "i=" << i << ", value=" << 3.14159 << endl;
    }
    auto end1 = high_resolution_clock::now();
    
    // 测试printf
    auto start2 = high_resolution_clock::now();
    for (int i = 0; i < n; i++) {
        printf("i=%d, value=%f\n", i, 3.14159);
    }
    auto end2 = high_resolution_clock::now();
    
    auto duration1 = duration_cast<milliseconds>(end1 - start1);
    auto duration2 = duration_cast<milliseconds>(end2 - start2);
    
    cout << "\n性能对比:" << endl;
    cout << "cout耗时: " << duration1.count() << "ms" << endl;
    cout << "printf耗时: " << duration2.count() << "ms" << endl;
    
    return 0;
}

一般来说:printf比cout快,特别是在大量输出时。


十、实用技巧

10.1 用sprintf格式化到字符串

#include <cstdio>
#include <string>
#include <iostream>
using namespace std;

int main() {
    char buffer[100];
    int year = 2024;
    int month = 3;
    int day = 15;
    
    // 格式化到字符串
    sprintf(buffer, "%04d-%02d-%02d", year, month, day);
    
    string date_str = buffer;  // 转换为string
    cout << "日期: " << date_str << endl;  // 2024-03-15
    
    return 0;
}

10.2 动态构建格式字符串

#include <cstdio>

int main() {
    int width = 10;
    int precision = 3;
    double value = 123.456789;
    
    // 动态构建格式字符串
    char format[20];
    sprintf(format, "%%%d.%df", width, precision);
    
    printf("格式字符串: %s\n", format);  // %10.3f
    printf(format, value);               //    123.457
    printf("\n");
    
    return 0;
}

10.3 清空输出缓冲区

#include <cstdio>

int main() {
    printf("正在处理...");
    fflush(stdout);  // 立即输出,不清缓冲区会等到换行才输出
    
    // 模拟耗时操作
    for (int i = 0; i < 100000000; i++);
    
    printf("完成!\n");
    
    return 0;
}

十一、从cout迁移到printf的速查表

你想输出…cout写法printf写法说明
整数cout << numprintf("%d", num)
浮点数(3位)fixed << setprecision(3) << numprintf("%.3f", num)常用
字符cout << chprintf("%c", ch)
字符串cout << strprintf("%s", str.c_str())注意.c_str()
换行cout << endlprintf("\n")
左对齐宽10left << setw(10) << numprintf("%-10d", num)
右对齐宽10right << setw(10) << numprintf("%10d", num)
补零宽5setfill('0') << setw(5) << numprintf("%05d", num)

十二、练习与测试

练习1:学生成绩单

#include <cstdio>

int main() {
    // 用printf输出以下成绩单:
    // 学号   姓名    语文  数学  英语  平均分
    // 001    张三    85.5  92.0  88.5  88.7
    // 002    李四    78.0  85.5  90.0  84.5
    
    printf("%-6s %-8s %-6s %-6s %-6s %-8s\n", 
           "学号", "姓名", "语文", "数学", "英语", "平均分");
    printf("--------------------------------------------\n");
    
    printf("%-6s %-8s %-6.1f %-6.1f %-6.1f %-8.1f\n", 
           "001", "张三", 85.5, 92.0, 88.5, (85.5+92.0+88.5)/3);
    printf("%-6s %-8s %-6.1f %-6.1f %-6.1f %-8.1f\n", 
           "002", "李四", 78.0, 85.5, 90.0, (78.0+85.5+90.0)/3);
    
    return 0;
}

练习2:计算圆的相关值

#include <cstdio>
#include <cmath>
#define PI 3.1415926535

int main() {
    double radius = 5.5;
    double area = PI * radius * radius;
    double circumference = 2 * PI * radius;
    
    printf("半径为 %.1f 的圆:\n", radius);
    printf("面积 = %.4f\n", area);
    printf("周长 = %.4f\n", circumference);
    
    return 0;
}

十三、总结

为什么学习printf?

  1. 简洁:一行代码完成复杂格式化
  2. 快速:执行效率通常比cout高
  3. 灵活:格式化控制非常强大
  4. 通用:C/C++都能用,很多老代码在用

给C++学习者的建议:

  1. 先掌握cout:因为它是C++的标准,类型安全
  2. 再学printf:需要时使用,特别是需要精确格式化时
  3. 混合使用:简单输出用cout,复杂格式化用printf

核心语法记忆:

// 基本模板
printf("格式字符串", 参数1, 参数2, ...);

// 常用格式
%d    // 整数
%.nf  // 浮点数,n位小数
%s    // 字符串
%c    // 字符

// 宽度和对齐
%10d   // 宽10,右对齐
%-10d  // 宽10,左对齐
%010d  // 宽10,补零

最后建议:

从今天开始,在需要格式化输出时尝试用printf代替cout,你会发现它真的很方便!特别是处理表格、对齐、精度控制时,代码会比cout简洁很多。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇