第十七章——输入输出

C++将输入输出视为字节流,通过流和缓冲区进行处理。iostream库提供了streambuf、ios_base、ios、ostream和istream等类来管理和操作这些流。cin、cout、cerr和clog是预定义的流对象,分别对应标准输入、输出、错误和日志流。ostream的<<运算符重载用于输出,而cin则用于处理输入,如read()、peek()和putback()等方法。此外,还可以使用width()、precision()和fill()等函数进行格式化输出。

C++输入和输出概述

流和缓冲区 

C++程序把输入和输出看作字节流。输入时,程序从输入流中抽取字节;输出时,程序将字节插入到输出流中

流充当了程序和流源或流目标之间的桥梁。这使得C++程序可以以相同的方式对待来自键盘的输入和来自文件的输入

 

通常使用缓冲区可以更高效地处理输入和输出。缓冲区是用作中介的内存块,是将信息从设备传输到程序或从程序传输给设备的临时存储工具。 

流、缓冲区和iostream文件

iostream文件中包含一些专门用来实现、管理流和缓冲区的类

  •  streambuf类为缓冲区提供了内存,并提供了用于填充缓冲区、访问缓冲区内容、刷新缓冲区和管理缓冲区内存的类方法
  • ios_base类表示流的一般特征,如是否可读取、是二进制流还是文本流等
  • ios类基于ios_base,其中包括了一个指向streambuf对象的指针
  • ostream类是从ios类派生而来的,提供了输出方法
  • istream类是从ios类派生而来的,提供了输入方法
  • iostream类是基于istream和ostream类的,因此继承了输入方法和输出方法

C++的iostream类库管理了很多细节

  • cin对象对应于标准输入流
  • cout对象与标准输出流相对应
  • cerr对象与标准错误流相对应,可用于显示错误消息。这个流没有缓冲,直接将信息发送给屏幕,而不会等到缓冲区填满或换新的换行符
  • clog对象也对应着标准错误流 

使用cout进行输出 

重载的<<运算符

 ostream类重新定义了<<运算符,将其重载为输出

除了各种operator<<()函数外,ostream类还提供了put()方法和write()方法,前者用于显示字符,后者用于显示字符串

put()方法的原型如下:

ostream & put(char);

可以用类方法表示法来调用它:

cout.put('W');

其中cout是调用方法的对象,put()是类成员函数 。在原型合适的情况下,可以将数值型参数(如int)用于put(),让函数原型自动将参数转化为正确char值,如

cout.put(65) << endl;
cout.put(68.3);

 

 write()方法显示整个字符串,其模板原型如下:

basic_ostream<charT,traits>& write(const char_type *s ,streamsize n);

第一个参数提供了要显示的字符串的地址,第二个参数指出要显示多少个字符

#include<iostream>
#include<cstring>
using namespace std;
int main()
{
	const char* statel = "Florida";
	const char* state2 = "Kansas";
	const char* state3 = "Euphoria";
	
	int len = strlen(state2);
	int i;
	cout << "Increasing loop index:\n";
	for (i = 1; i <= len; i++)
	{
		cout.write(state2, i);
		cout << endl;
	}
	cout << "Decreasing loop index:\n";
	for (i = len; i > 0; i--)
	{
		cout.write(state2, i) << endl;
	}
	cout << "Exceeding string length:\n";
	cout.write(state2, len + 5) << endl;
	return 0;
}

 

注意cout.write()调用返回cout对象。 

使用cout进行格式化

可以使用width成员函数将长度不同的数字放到宽度相同的字段中

int width();
int width(int i);

 第一种格式返回字段宽度的当前设置;第二种格式将字段宽度设置为i个空格,并返回以前的字段宽度值

注意width()方法只影响接下来显示的一个项目,然后字段宽度将恢复为默认值

填充字符

在默认情况下,cout用空格填充未被使用的部分,可以用fill()成员函数来改变填充字符,例如下面的函数调用将填充字符改为星号:

cout.fill('*');

设置浮点数的精度

 浮点数精度的含义取决于输出模式,在默认模式下,它指的是显式的总位数。在定点模式和科学模式下,精度指的是小数点后面的位数。C++ 的默认精度为6位,precision()成员函数使得能够选择其他值,如下面语句将cout的精度设置为2:

cout.precision(2);

 头文件iomanip

C++在头文件中提供了其他一些控制符,3个最常见的控制符分别是setprecision()、setfill()、和setw(),它们分别用来设置精度、填充字符和字符宽度。

使用cin进行输入

cin对象将标准输入表示为字节流,通常用键盘来生成这种字符流。 

除了前面已经介绍过的外,其他istream方法包括read(),peek(),gcount(),putback()

read()函数读取指定数目的字节,并将它们存储在指定的位置中

peek()函数返回输入中的下一个字符,但不抽取输入流中的字符

gcount()函数返回最后一个非格式化抽取方法读取的字符数。这意味着字符是由get()、getline()、ignore()或read()方法读取的,而不是由抽取运算符(>>)读取的,抽取运算符对输入进行格式化,使之与特定数据类型匹配

putback()函数将一个字符插入到字符串中,被插入的字符将是下一条输入语句读取的第一个字符。

你遇到的问题是:**输入一个15位身份证号,程序输出了两个结果拼在一起(如 `420111200208014014420111190208014018`)**,说明程序可能被运行了两次,或者有逻辑错误导致重复处理。 但我们先来 **分析这个测试用例**: --- ### ✅ 测试输入: ``` 420111020801401 ``` 我们一步步转换为18位身份证。 --- ### 🔍 步骤 1:插入年份前缀 - 原始 ID:`420111020801401` - 第7到第12位是 `020801` → 出生日期是 `02`年`08`月`01`日 → 即 2002 年出生 - 题目说:“假设所有人均出生于1905年以后,2005年以前” - 所以包括 2000–2004 年出生的人 📌 关键点来了: > **题目中说“在第六位后插入19(1905年后)或20(2000.1.1-2004.12.31出生)”** 所以对于 **2002年出生** 的人,应该插入的是 `'20'`,而不是 `'19'`! 但之前的代码统一插入 `'19'`,这是 **错误的**! --- ### ✅ 正确逻辑修正: 我们需要判断出生年份: - 如果 YY < 100 → 实际年份是 19YY 或 20YY - 根据题意: - YY ≥ 05 → 19YY(如 85 → 1985) - YY ≤ 04 → 20YY(如 02 → 2002) 👉 所以从第7、8位取 `YY` = `int(id_15[6:8])` - 若 YY >= 5 → 插入 `'19'` - 若 YY <= 4 → 插入 `'20'` --- ### ✅ 修正后的正确代码: ```python id_15 = input().strip() # 提取年份部分 year_short = int(id_15[6:8]) # 判断插入 '19' 还是 '20' if year_short >= 5: prefix = '19' else: prefix = '20' # 构造17位身份证 id_17 = id_15[:6] + prefix + id_15[6:] # 加权因子 weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2] # 校验码映射 check_codes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'] # 计算加权和 total = 0 for i in range(17): total += int(id_17[i]) * weights[i] # 取模得到校验码 Y = total % 11 check_digit = check_codes[Y] # 输出完整18位身份证 print(id_17 + check_digit) ``` --- ### ✅ 验证输入:`420111020801401` - `id_15 = '420111020801401'` - `year_short = int('02') = 2` → 小于5 → 插入 `'20'` - `id_17 = '420111' + '20' + '020801401' = '42011120020801401'` - 现在计算前17位加权和: #### 手动计算部分验证: id_17 = `4 2 0 1 1 1 2 0 0 2 0 8 0 1 4 0 1` weights = `[7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2]` 逐项相乘: | i | digit | weight | product | |---|-------|--------|---------| |0|4|7|28| |1|2|9|18| |2|0|10|0| |3|1|5|5| |4|1|8|8| |5|1|4|4| |6|2|2|4| |7|0|1|0| |8|0|6|0| |9|2|3|6| |10|0|7|0| |11|8|9|72| |12|0|10|0| |13|1|5|5| |14|4|8|32| |15|0|4|0| |16|1|2|2| Sum = 28+18+0+5+8+4+4+0+0+6+0+72+0+5+32+0+2 = **184** Y = 184 % 11 = 184 ÷ 11 = 16×11=176 → 余数 = **8** 查表:余数8 → 校验码 `'4'` ✅ 所以最终身份证号:`420111200208014014` --- ### ✅ 正确输出: ``` 420111200208014014 ``` --- ### ❌ 为什么你会看到两个结果拼接? 比如: ``` 420111200208014014420111190208014018 ``` 这说明你的代码可能: 1. 被执行了两次(比如误读输入多次) 2. 或者你在某个地方写了两个 `print` 3. 或者你用了旧代码(统一插19),然后又运行了一次新逻辑 > 比如:第一次按 `20` 处理得 `...4014`,第二次按 `19` 处理得 `...4018`,然后都打印了 --- ### ✅ 最终结论: ✅ 正确答案是: ```python 420111200208014014 ``` 使用上面修正后的代码即可正确输出。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值