【C++ 输入输出】cin、cout、cerr 与格式化输出

1. 为什么需要输入输出?

程序需要与用户"交流":输出 让程序告诉用户结果,输入 让用户告诉程序数据。C++ 通过 <iostream> 库提供了三个最常用的流对象:

对象 含义 默认连接
cin 标准输入 键盘
cout 标准输出 屏幕
cerr 标准错误 屏幕(无缓冲,立即显示)

2. 基本使用:cin、cout、cerr

示例1:读取两个整数并输出它们的和

cpp 复制代码
#include <iostream>
using namespace std;

int main() {
    int a, b;
    cout << "请输入两个整数:";
    cin >> a >> b;
    int sum = a + b;
    cout << "它们的和是:" << sum << endl;
    return 0;
}

运行示例 (假设输入 10 20):

复制代码
请输入两个整数:10 20
它们的和是:30

示例2:使用 cerr 输出错误信息

cpp 复制代码
#include <iostream>
using namespace std;

int main() {
    int age;
    cout << "请输入年龄(0-120):";
    cin >> age;
    if (age < 0 || age > 120) {
        cerr << "错误:年龄超出合理范围!" << endl;
        return 1;   // 非0返回表示异常
    }
    cout << "您的年龄是:" << age << endl;
    return 0;
}

注意cerr 不受输出重定向影响,通常用于错误信息,且不经过缓冲区(立即显示)。

3. 格式化输出(iomanip 库)

C++ 提供了 <iomanip> 头文件中的操作符,用于精细控制输出格式。

3.1 控制整数进制

cpp 复制代码
#include <iostream>
#include <iomanip>
using namespace std;

int main() {
    int num = 255;
    cout << "十进制:" << dec << num << endl;   // 255
    cout << "十六进制:" << hex << num << endl; // ff
    cout << "八进制:" << oct << num << endl;   // 377
    // 恢复十进制
    cout << dec << "恢复十进制:" << num << endl;
    return 0;
}

3.2 控制浮点数精度与格式

cpp 复制代码
#include <iostream>
#include <iomanip>
using namespace std;

int main() {
    double pi = 3.1415926535;
    // 设置固定小数位数(小数点后2位)
    cout << fixed << setprecision(2) << pi << endl; // 3.14
    // 科学计数法
    cout << scientific << setprecision(4) << pi << endl; // 3.1416e+00
    // 恢复默认浮点输出(自动选择)
    cout << defaultfloat << pi << endl;
    return 0;
}

3.3 设置宽度与填充字符

cpp 复制代码
#include <iostream>
#include <iomanip>
using namespace std;

int main() {
    cout << setw(10) << "ID" << setw(10) << "Name" << endl;
    cout << setw(10) << 1001 << setw(10) << "Alice" << endl;
    cout << setw(10) << 1002 << setw(10) << "Bob" << endl;
    // 填充字符改为 '*'
    cout << setfill('*') << setw(10) << 1003 << setw(10) << "Tom" << endl;
    return 0;
}

输出:

复制代码
        ID      Name
      1001     Alice
      1002       Bob
******1003*******Tom

4. 内存模型讲解(浅显易懂)

当我们执行 cin >> acout << "hello" 时,背后发生了什么?来看内存中的"输入输出缓冲区"模型。

复制代码
用户键盘输入 "10 20\n"
       ↓
┌─────────────────────────────────────────┐
│              输入缓冲区 (内存)          │
│  [ '1' , '0' , ' ' , '2' , '0' , '\n' ] │
└─────────────────────────────────────────┘
       ↓  cin 从缓冲区解析整数
       ↓
┌──────────────┐   ┌──────────────┐
│  变量 a (栈) │   │  变量 b (栈) │
│    10        │   │    20        │
└──────────────┘   └──────────────┘
  • 输入缓冲区 :当你在键盘上敲击并按下回车,操作系统把字符序列存入内存中的"输入缓冲区"。cin 从该缓冲区读取并转换成对应类型(比如 int)。
  • 输出缓冲区cout << "结果:" << sum << endl; 先将数据写入"输出缓冲区"(内存中的一块区域),当遇到 endl 或缓冲区满时,系统才真正把内容显示到屏幕(或写入文件)。这样做是为了提高效率(减少慢速 I/O 操作)。

cerr 的特殊性cerr 不经过缓冲区,直接输出到屏幕。这意味着即使程序崩溃,错误信息也能立即显示,不会因为缓冲区没刷新而丢失。

5. 常见错误与避坑

错误写法 问题
cin >> a, b; 逗号不能用于连续输入,应使用 >> 连接:cin >> a >> b;
输入 10 20 但变量类型是 char 类型不匹配,cin 会失败,后续读取无效
cout << setprecision(2) << 3.1415; 没有 fixed 设置的是总有效位数,而不是小数位数
忘记 #include <iomanip> 使用 setwsetprecision 等会编译错误
cerrcout 混用导致顺序奇怪 因为 cout 有缓冲,cerr 无缓冲,可能先显示 cerr 内容再显示 cout

6. 练习题

题目:编写一个程序,要求:

  1. 提示用户输入一个浮点数(例如 123.456789)。
  2. 读取该浮点数,并分别用以下格式输出:
    • 默认格式(保留6位有效数字)
    • 固定小数点后3位
    • 科学计数法(小数点后4位)
  3. 再提示用户输入一个整数(例如 255),分别以十进制、十六进制、八进制输出,每个数占宽8格,用 0 填充前导空白。

示例输入

复制代码
123.456789
255

期望输出

复制代码
默认格式:123.457
固定3位小数:123.457
科学计数法:1.2346e+02
十进制:00000255
十六进制:000000ff
八进制:00000377

提示

  • 使用 fixedscientificsetprecisionsetwsetfillhexoctdec
  • 切换进制后如需恢复十进制,记得使用 dec

上期练习答案

cpp 复制代码
#include <iostream>
using namespace std;

int main() {
    cout << "My name is Alice" << endl;
    cout << "I am learning C++!" << endl;
    return 0;
}

总结 :今天我们学习了 C++ 的标准输入输出 cincoutcerr,掌握了使用 <iomanip> 进行格式化输出的常用方法,并理解了缓冲区在内存中的作用。下一篇文章我们将深入注释与编码风格,继续夯实基础。

快去动手写代码,用格式化输出做出漂亮的报告吧!

相关推荐
c238569 分钟前
互斥锁高频面试题全解:从基础概念到底层实现,一文通关
java·c++·面试·职场和发展
北冥you鱼19 分钟前
Go 语言读取链上数据:从基础到实战
开发语言·后端·golang
nianniannnn20 分钟前
c++复习自存--继承
开发语言·c++
kebidaixu43 分钟前
两轮BMS 防打火策略详解
算法
wabs6661 小时前
关于动态规划【力扣1035.不相交的线和53.最大子数组和的思考】
算法·leetcode·动态规划
退休倒计时1 小时前
【每日一题】LeetCode 199. 二叉树的右视图 TypeScript
算法·leetcode·typescript
可编程芯片开发1 小时前
通过MATLAB实现PID控制器,积分分离控制器以及滑模控制器
算法
叩码以求索2 小时前
经典算法实例分析:写字符串需要的行数
开发语言·javascript·ecmascript
我是唐青枫2 小时前
Kotlin 运算符重载详解:为什么 a += b 有时改对象,有时换对象?
开发语言·kotlin
2zcode2 小时前
基于MATLAB图像处理的饮料瓶识别与价格显示系统设计与实现
开发语言·图像处理·matlab