在C++中,输入输出流(I/O)是一个强大的特性,它允许程序与各种输入/输出设备(如键盘、显示器、文件等)进行交互。C++标准库中的<iostream>头文件定义了基本的输入输出流类,如std::cin(用于输入)、std::cout(用于输出)和std::cerr(用于错误输出)。
这篇将通过一些实例进一步了解输入输出流的相关知识。
一、标准输出流
题目:输入三角形的三边a,b,c,计算三角形的面积的公式是:
构成三角形的条件是:a+b>c,b+c>a,c+a>b
编写程序,输入a,b,c检查a,b,c是否满足以上条件,如不满足,由cerr输出有关出错信息。
解释:此题相对较容易,只要输入三个数值满足三角形条件即可,例如:10、15、20。通过cin输入10 15 20后,使用if判断,当三个条件都不满足时并且在前面添加非(!)则为true,显示错误信息。如果都满足,则进后后续计算并输出结果。
示例代码如下:
#include <iostream>
#include <cmath>
using namespace std;
int main(){
float a, b, c, s, area; // 定义变量
// 输出a,b,c数值
cin >>a >>b >>c;
// 判断条件
if(!((a + b > c) && (b + c > a) && (c + a > b))) {
cerr <<"The entered values a,b, and c do not meet the conditions" <<endl;
} else{
// 满足条件情况下进行计算
s = (a + b + c) / 2; // 计算出s的值
// 计算面积的值
area = sqrt(s * (s - a) * (s - b) * (s - c));
// 输出结果
cout <<"Result:" <<area <<endl;
}
return 0;
}
运行后结果如下图:
二、格式输出与字符串流
题目:从键盘输入一批数值,要求保留3位小数,在输出时上下行小数点对齐。
解释:此题将通过三块知识来实现:
- 首先是通过iostream类中的cin输入和cout输出,从键盘获取数据并输出显示结果;
- 再通过sstream类中的ostringstream输出字符串流对象,将最大值max转换为字符串并赋值给string类型变量str;再通过string类型中的size()函数获取字符长度,作为每行显示的最大宽度。
- 最后设置格式状态,按题中要求进行输出显示。
示例代码如下:
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main(){
double nums[3];
cout <<"Please enter the value" <<endl;
// 输入数值
for(int i = 0; i < 3; i++) cin >>nums[i];
cout <<endl;
// 计算出最大值,以便获取每行数据显示最大宽度值
double max = nums[0];
for(int i = 1; i < 3; i++) if(max < nums[i]) max = nums[i];
// 装载到输出字符串流中
ostringstream oss;
// 插入字符串数据
oss <<max;
// 将字符串流 赋值给string类型变量str
string str = oss.str();
// 对齐输出三位数
cout.precision(3); // 保留3位小数
cout.setf(ios::fixed); // 以浮点数格式输出
cout.setf(ios::right); // 右对齐
// 循环输出
for(int i = 0; i < 3; i++) {
cout.width(str.size()); //通过最大值获取每行最大显示范围
cout <<nums[i] <<endl;
}
return 0;
}
运行后结果如下图:
三、输出三角形
题目:在显示屏上显示一个由字母B组成的三角形。
解释:此题要实现由字母B组成的三角形,则需要使用嵌套for循环。每行的前半部分得先输出空格字符来占位,后部分再输出B字母。另外还须保证每行输出字母B的个数为奇数,这样才能保证每列中字母是竖向对齐。下面代码中几点的说明:
- 当在 i 的值偶数行时输出;
- 虽然size为20,但i<size并且为偶数行时才输出,所以此三角形只显示10行。
- 前半部分通过m<(size-i)/2限制,所以只能输出1~9个空格字符;第一行中前半部分输出9个空字符,第10位刚显示显示字母B,在三角形正中间位置。
- 后部分由于n>=0,所以i为0且i%2==0时,第一行输入一个字母B;当i为2且i%2==0时,n满足条件值为0,1,2输出三个字母B;当i为4且i%2==0时,n满足条件值为0,1,2,3,4输出5个字母B。以此类推,则每行显示字母B个数都为奇数。
示例代码:
#include <iostream>
using namespace std;
int main(){
int size = 20;
for(int i = 0; i < size; i++){
// 偶数部分输出
if(i%2==0){
// 前半部分(空白填充)
for(int m = 0; m < (size - i)/2; m++) cout <<" ";
// 后部分(输出字符B)
for(int n = i; n < size && n >= 0; n--) cout <<"B";
cout <<endl;
}
}
return 0;
}
运行后结果如下图:
四、输入和输出文件流
建立两个磁盘文件file1.txt和file2.txt,编程序实现以下工作:
(1)题目一:创建并存储数据
从键盘输入20个数,分别存放在两个磁盘文件中(每个文件中放10个整数);
示例代码如下:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main(){
// 定义文件名称
string file1 = "file1.txt", file2 = "file2.txt";
int len = 20; // 定义整数长度
int nums[len]; // 定义数组存储数值
// 输入20个整数,并分别存入两个文件中
cout <<"Please enter 20 integer values:" <<endl;
for(int i = 0; i < len; i++) cin >>nums[i];
ofstream ofs; // 定义输出文件流对象
ofs.open(file1); // 打开file1.txt文件,并输出
if(!ofs.is_open()){
cerr <<"Open " <<file1 <<" error.";
exit(1);
} else{
// 插出数据
for(int i = 0; i < len; i++) ofs <<nums[i] <<' ';
}
ofs.close(); // 关闭流文件
ofs.open(file2); // 打开file2.txt
if(!ofs.is_open()){
cerr <<"Open " <<file2 <<" error.";
exit(1);
} else{
// 插出数据
for(int i = 0; i < len; i++) ofs <<nums[i] <<' ';
}
ofs.close(); //关闭流文件
return 0;
}
运行后结果如下图:
执行后,目录中侧生成file1.txt和file2.txt文件,并且内部已存入相同的20个整数值。如下图:
(2)题目二:读取并追加数据
从file1.txt读入10个数,然后存放到file2.txt文件原有数据的后面;
示例代码如下:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main(){
// 定义文件名称
string file1 = "file1.txt", file2 = "file2.txt";
// 定义整数长度
int len = 10;
// 定义数组存储数值
int nums[len];
ifstream ifs(file1); // 定义输入文件流对象,并打开file1.txt文件
// 将数据存储数组num2中
for(int i = 0; i < len; i++) {
ifs >>nums[i];
cout <<nums[i] <<" ";
}
// 写入到file2.txt文件中,并追加
ofstream ofs(file2, ios::app); // 定义输出文件流对象
for(int i = 0; i < len; i++) ofs <<nums[i] <<' ';
return 0;
}
运行结果如下图:
此时file2.txt中则追加了file1.txt前10个整数,ios::app为打开文件并在后追加数据方式。如下图:
(3)题目三:读取并排序
从file2.txt中读入20个整数,将它们按小到大的顺序存放到file2.txt(不保留原来的数据)。
示例代码:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main(){
// 定义文件名称
string file2 = "file2.txt";
int len = 20; // 定义整数长度
// 定义数组存储数值
int nums[len];
ifstream ifs(file2); // 定义输入文件流对象,并打开file2.txt文件
// 将数据存储数组num2中
for(int i = 0; i < len; i++) ifs >>nums[i];
// 对数组nums进行排序(冒泡排序)
int temp;
for(int i = 0; i < len - 1; i++){
for(int j = i + 1; j < len; j++){
if(nums[i] > nums[j]){
temp = nums[j];
nums[j] = nums[i];
nums[i] = temp;
}
}
}
// 覆盖写入到file2.txt文件中
ofstream ofs(file2); // 定义输出文件流对象
for(int i = 0; i < len; i++) {
cout <<nums[i] <<' '; //输出控制台显示结果
ofs <<nums[i] <<' '; //输出到file2.txt文件中
}
return 0;
}
运行后结果如下图:
此时file2.txt中则为排序后整数,之前内容直接被覆盖。如下图:
五、二进制文件的操作
编程序实现以下功能:
(1)题目一:创建对象并存储
按职工号由小到大的顺序将5个员工的数据(包括职工号、姓名、年龄、工资)输出到磁盘文件中保存。
示例代码:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
// 定义员工类
class Employee{
private:
int num;
char name[50];
int age;
float wage;
public:
Employee(int num, const char* nameStr, int age, float wage):
num(num), age(age), wage(wage){
strncpy(name, nameStr, sizeof(name) - 1); // 复制nameStr到name,并确保最后一个字符是'\0'
name[sizeof(name) - 1] = '\0';
}
// 打印学员信息
void print() const {
cout <<"num:" <<num <<", name:" <<name <<", age:" <<age <<", wage:" <<wage <<endl;
}
};
int main(){
// 定义员工类数组,存储5位员工信息
Employee s[5] = {
Employee(100, "Tom", 30, 5000.0f),
Employee(101, "John", 29, 5500.0f),
Employee(102, "Lily", 29, 5500.0f),
Employee(103, "Marry", 24, 4500.0f),
Employee(104, "Make", 23, 4500.0f)
};
// 定义输出文件流对象
ofstream outfile("employee.txt", ios::binary);
if(!outfile){
cerr <<"Open employee.txt error.";
abort();
}
// 循环输出员工信息
for(int i = 0; i < 5; i++){
outfile.write((char *)&s[i], sizeof(s[i]));
}
outfile.close(); //关闭文件流
return 0;
}
运行后文件以二进制形式输出并存储到employee.txt文件中,如下图:
(2)题目二:追加员工信息
从键盘输入两个员工的数据(职工号大于已有的职工号),增加到文件的末尾。
示例代码:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
// 定义员工类
class Employee{
private:
int num;
char name[50];
int age;
float wage;
public:
Employee(){}
Employee(int num, const char* nameStr, int age, float wage):
num(num), age(age), wage(wage){
strncpy(name, nameStr, sizeof(name) - 1); // 复制nameStr到name,并确保最后一个字符是'\0'
name[sizeof(name) - 1] = '\0';
}
// 打印学员信息
void print() const {
cout <<"num:" <<num <<", name:" <<name <<", age:" <<age <<", wage:" <<wage <<endl;
}
};
int main(){
// 定义员工类数组,存储新员工信息
Employee s[2];
// 定义临时变化接收输入数据
int num, age;
char name[50];
float wage;
for(int i = 0; i < 2; i++){
cout <<"Please enter your employee information:" <<endl;
cin >>num >>name >>age >>wage;
s[i] = Employee(num, name, age, wage);
}
// 定义输出文件流对象
ofstream outfile("employee.txt", ios::binary|ios::app);
if(!outfile){
cerr <<"Open employee.txt error.";
abort();
}
// 循环输出员工信息
for(int i = 0; i < 2; i++){
outfile.write((char *)&s[i], sizeof(s[i]));
}
outfile.close(); //关闭文件流
return 0;
}
运行后结果如下图:
此时employee.txt文件中已追加两条数据,如下图:
(3)题目三:读取全部员工信息
输出文件中全部职工的数据。
示例代码:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
// 定义员工类
class Employee{
private:
int num;
char name[50];
int age;
float wage;
public:
Employee(){}
Employee(int num, const char* nameStr, int age, float wage):
num(num), age(age), wage(wage){
strncpy(name, nameStr, sizeof(name) - 1); // 复制nameStr到name,并确保最后一个字符是'\0'
name[sizeof(name) - 1] = '\0';
}
// 打印学员信息
void print() const {
cout <<"num:" <<num <<", name:" <<name <<", age:" <<age <<", wage:" <<wage <<endl;
}
};
int main(){
// 定义文件流对象,读取员工信息
ifstream infile("employee.txt", ios::binary);
if(!infile){
cerr <<"Open employee.txt error.";
abort();
}
// 定义数组,存储员工信息
Employee list[7];
for(int i = 0; i < 7; i++){
infile.read((char*)&list[i], sizeof(list[i])); // 将数据写入到数组中
list[i].print();
}
infile.close();
return 0;
}
运行后结果如下图:
(4)题目四:查询员工信息
从键盘输入一个号码,从文件中查找有无此职工号,如有则显示此职工是第几个职工,以及此职工的全部数据。如有没,就输出“无此人”。可以反复多次查询,如果输入查找的职工号为0,就结束查询。
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
// 定义员工类
class Employee{
private:
int num;
char name[50];
int age;
float wage;
public:
Employee(){}
Employee(int num, const char* nameStr, int age, float wage):
num(num), age(age), wage(wage){
strncpy(name, nameStr, sizeof(name) - 1); // 复制nameStr到name,并确保最后一个字符是'\0'
name[sizeof(name) - 1] = '\0';
}
// 获取职工号
int getNum() const{
return num;
}
// 打印学员信息
void print() const {
cout <<"num:" <<num <<", name:" <<name <<", age:" <<age <<", wage:" <<wage <<endl;
}
};
int main(){
// 定义文件流对象,读取员工信息
ifstream infile("employee.txt", ios::binary);
if(!infile){
cerr <<"Open employee.txt error.";
abort();
}
// 定义数组,存储员工信息
Employee list[7];
for(int i = 0; i < 7; i++){
infile.read((char*)&list[i], sizeof(list[i])); // 将数据写入到数组中
list[i].print();
}
cout <<endl;
infile.close();
// 执行查询
int num; // 定义接收num变量
do{
cout <<"Please enter the employee number:" ;
cin >>num; // 输入职工号
// 开始查询
int index; //索引
Employee* e = nullptr;
for(int i = 0; i < 7; i++){
if(list[i].getNum() == num){
index = i + 1;
e = &list[i];
}
}
// 如果员工存在,则显示结果
if(e != nullptr){
cout <<"Index:" <<index <<endl;
e->print();
}
// 不存在,显示“查无此人”
else if(num != 0) cout <<"No such person" <<endl;
else if(num == 0) cout <<"End of query." <<endl;
cout <<endl;
} while(num != 0); //num不为0则继承查询
return 0;
}
运行结果如下图: