C++——IO流

C语言中我们学习过文件IO的相关函数,那么在C++中也一定有各种IO流的
函数或者功能,由我今天来简单介绍一下C++中IO流的大致原理及使用。

在C语言中我们经常会使用到scanf、printf、sscanf、sprintf等等来实现进程和文件之间数据的流动,在C++中虽然由于面向对象的特性使得C++和C语言的文件IO不一样,但他们都有IO流的说法,那么说到很多次“流”这个字,那么“流”究竟是什么?

1. 流的简单认识

“流”即是流动的意思,是物质从一处向另一处流动的过程,是对一种有序连续且具有方
向性的数据( 其单位可以是bit,byte,packet )的抽象描述。C++流是指信息从外部输入
设备(如键盘)向计算机内部(如内存)输入和从内存向外部输出设备(显示器)输出
的过程。这种输入输出的过程被形象的比喻为“流”。
它的特性是:有序连续、具有方向性。

那我们们直接步入主题,来认识C++中的IO流

2. C++IO流

a. C++IO特点

在这里插入图片描述
C++中的IO体系中,使用了基类派生类的方式,以一个最基本的IO方式来衍生出各种合适的IO方式。和C语言有区别的是,C语言中是有着stdin、stdout、stderr。而C++中有cin、cout、cerr、clog,多了个clog,它们的基本特性还是差不多,例如cin和scanf一样默认以空格和换行作为隔断,不同的是C语言中是格式化输入输出,而C++中没有这一直接功能,而是需要使用函数来实现:
在这里插入图片描述
比如这一函数就是用来控制浮点数的精度:

在这里插入图片描述
这里后面出现了26是因为计算机存储浮点数精度的问题。
但是C++中解决了一个问题,那就是C语言无法对自定义类型有着很好的输出输入:

class Student
{friend istream& operator>>(istream& in, Student& st);friend ostream& operator<<(ostream& out, Student& st);
private:string name;string id;int age;
};istream& operator>>(istream& in, Student& st)
{in >> st.name >> st.id >> st.age;return in;
}ostream& operator<<(ostream& out, Student& st)
{out << "姓名:" << st.name << endl <<"学号:" <<  st.id << endl << "年龄:" << st.age << endl;return out;
}int main()
{Student s;cin >> s;cout << s;return 0;
}

在这里插入图片描述
这在C语言中写的可就不止这两行了。
还有在oj题中我们经常会遇到下面的代码:

int main()
{int a = 0;while (cin >> a){}return 0;
}

可是我们知道,流提取的返回值是ostream&类型的,但是我们while中判断的值直接判断的是bool,或者整型值也可以作为判断的依据,那么凭什么ostream类型能够作为判断依据呢?这是因为:
在这里插入图片描述
它的成员函数中重载了bool,可以让ostream转为bool类型,这也算是一种重载,但是跟普通的重载不一样,它没有返回值,就可以实现这样的玩法:
在这里插入图片描述

在这里插入图片描述

class Student
{friend istream& operator>>(istream& in, Student& st);friend ostream& operator<<(ostream& out, Student& st);public:operator bool(){if (name == "aaa")return false;else return true;}operator int(){return 1;}private:string name;string id;int age;
};istream& operator>>(istream& in, Student& st)
{in >> st.name >> st.id >> st.age;return in;
}ostream& operator<<(ostream& out, Student& st)
{out << "姓名:" << st.name << endl <<"学号:" <<  st.id << endl << "年龄:" << st.age << endl;return out;
}int main()
{Student st;while(cin >> st){if (st)cout << "hello world" << endl;else{int a = st;cout << a << endl;}}return 0;
}

b. C++文件IO

跟C语言一样对于文件IO操作都是以f开头。
在这里插入图片描述
关于文件IO,有两种方式,一种是二进读写,一种是文本读写,二进制读写是当你写到文件的数据形式是二进制,无法直接观看,而文本读写就是,以字符串的方式来写入文件中,可以直接观察:
我们使用一个类来封装一下文件IO:

class Student
{friend istream& operator>>(istream& in, Student& st);friend ostream& operator<<(ostream& out, Student& st);public:operator bool(){if (name == "aaa")return false;else return true;}operator int(){return 1;}//private:char name[10];char id[20];int age;
};istream& operator>>(istream& in, Student& st)
{in >> st.name >> st.id >> st.age;return in;
}ostream& operator<<(ostream& out, Student& st)
{out << "姓名:" << st.name << endl <<"学号:" <<  st.id << endl << "年龄:" << st.age << endl;return out;
}class FileIO
{
public:FileIO(string s):_filename(s){}void BinRead(Student& st){ifstream ifs(_filename, ios_base::in | ios_base::binary);ifs.read((char*)&st, sizeof(st));}void BinWrite(Student& st){ofstream ofs(_filename, ios_base::out | ios_base::binary);ofs.write((const char*)&st, sizeof(st));}void TextRead(Student& st){ifstream ifs(_filename);ifs >> st.name >> st.id >> st.age;}void TextWrite(Student& st){ofstream ofs(_filename);ofs << st.name <<endl << st.id  << endl<< st.age;}private:string _filename;
};int main()
{FileIO fio1("test1.txt");Student st, st1, st2;cin >> st;fio1.BinWrite(st);fio1.BinRead(st1);cout << st1 << endl;FileIO fio2("test2.txt");cin >> st;fio2.TextWrite(st);fio2.TextRead(st2);cout << st2 << endl;return 0;
}

在这里插入图片描述

在这里插入图片描述

有人可能注意到,我对Student类做了一些小改动,我改变了它的成员变量,将string变成了char的数组,那我们假如使用string呢?
VS2022下
在这里插入图片描述
文件中
在这里插入图片描述
这与我们刚开始的结果并不一样。这里明显多了一些东西,那假如我们,重新运行程序只进行读呢?
在这里插入图片描述
存的东西再长一些呢?
在这里插入图片描述
直接崩了
在这里插入图片描述

这是因为自定义类型数组,是在栈上,在二进制读写的时候就是把自己数组的内容直接写进文件中了,但是自定义类型string不一样,它的内部结构我们大致直到应该是一个char*、size_t、size_t类型的,他的字符串是存在堆上的我们要进行写的时候,会把string中的char*的地址写到文件中,两个整形写到文件中。
在这里插入图片描述

如果我们这个时候结束程序,系统会回收我们的资源,但是我们文件中存的还是那个地址,那么再次打开程序读那个地址,发生访问越界问题那自然就崩了。
在这里插入图片描述

而在同一程序下进行读写的时候则是因为同一进程还没有回收资源,那个地址指向的仍然是我们的字符串,那为什么还是崩了呢?这个是因为,发生了浅拷贝的原因,st和st1中的string指向的地址是同一个,在main函数结束的时候,会释放两次,所以还是会崩。
在这里插入图片描述
还有一个问题,那为什么短一点的字符串看起来没有上面的在两个进程下读写崩了呢?那是因为VS编译器中的string中有一段自己的缓存区。
所以:使用二进制读写时,尽量不要用容器

c. 内存间IO

我们在C语言中如果要将一个整形转成字符串或者字符串转成整形会怎么办呢?我们可能会使用函数atoi、itoa,但是我们还有一种方法,就是使用ssprintf、sscanf:
在这里插入图片描述
负数也可以:
在这里插入图片描述
而在C++中自然也可以有这种方式:
在这里插入图片描述
那就是sstream。

1). 字符串整数之间转换

int main()
{//整数转字符串int a = 123456;string s;stringstream ssm;ssm << a;ssm >> s;cout << s << endl;//字符串转整数ssm.clear();ssm << s;int b = 0;ssm >> b;cout << b << endl;return 0;
}

在这里插入图片描述

clear()注意多次转换时,必须使用clear将上次转换状态清空掉, stringstreams在转换结尾时(即最后一个转换后),会将其内部状态设置为badbit,因此下一次转换是必须调用clear()将状态重置为goodbit才可以转换,但是clear()不会将stringstreams底层字符串清空掉s.str("");
将stringstream底层管理string对象设置成"", 否则多次转换时,会将结果全部累积在底
层string对象中

2). 字符串拼接

int main()
{string s1 = "hello";string s2 = "world";stringstream ssm;ssm << s1;ssm << s2;string s3;ssm >> s3;cout << s3 << endl;return 0;
}

在这里插入图片描述

3). 结构化数据

class Student
{friend istream& operator>>(istream& in, Student& st);friend ostream& operator<<(ostream& out, Student& st);
public:Student(string name = "", string id = "", int age = 0):_name(name),_id(id),_age(age){}string _name;string _id;int _age;
};istream& operator>>(istream& in, Student& st)
{in >> st._name >> st._id >> st._age;return in;
}ostream& operator<<(ostream& out, Student& st)
{out << "姓名:" << st._name << endl <<"学号:" <<  st._id << endl << "年龄:" << st._age << endl;return out;
}int main()
{Student st("张三", "2024", 12);stringstream ssm;ssm << st._name << " " << st._id << " " << st._age;Student st1;ssm >> st1._name >> st1._id >> st1._age;cout << st1 << endl;return 0;
}

在这里插入图片描述

4). 小点总结

  1. stringstream实际是在其底层维护了一个string类型的对象用来保存结果。
  2. 多次数据类型转化时,一定要用clear()来清空,才能正确转化,但clear()不会将
    stringstream底层的string对象清空。
  3. 可以使用s. str(“”)方法将底层string对象设置为""空字符串。
  4. 可以使用s.str()将让stringstream返回其底层的string对象。
  5. stringstream使用string类对象代替字符数组,可以避免缓冲区溢出的危险,而且其会对参
    数类型进行推演,不需要格式化控制,也不会出现格式化失败的风险,因此使用更方便,更
    安全。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/650720.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python黑马模块

1、使用内置模块 # import通过.使用模块内部的全部功能 """ import time print("ff") time. sleep(5) print("as")# 使用from 导入某个功能 from time import sleep print("ff") sleep(5) print("as")# 使用 * 导入全部…

taskflow 源码阅读笔记-1

之前写了一篇介绍Taskflow的短文&#xff1a;传送门 Taskflow做那种有前后依赖关系的任务管理还是不错的&#xff0c;而且他的源码里运用了大量C17的写法&#xff0c;觉得还是非常值得学习的&#xff0c;因此决定看一下他的源码&#xff0c;这里顺便写了一篇代码学习笔记。 概…

Amazon 亚马逊新玩具——在线购物试衣服“虚拟试穿”模型:Diffuse to Choose

这个模型拥有强大的能力&#xff0c;它能够将任何商品无缝地融入任何环境之中&#xff0c;确保商品与环境完美匹配。例如&#xff0c;你可以轻松地将在线商店中的椅子图片放入你客厅照片中&#xff0c;预览它实际摆放的效果。无论环境如何变化&#xff0c;该模型都能确保商品展…

Java复习系列之阶段二:数据库

1. 基础语法 1.1 DQL&#xff08;数据查询语句&#xff09; 执行顺序&#xff1a; from、join 、on、where、group by、having、select、distinct、order by、limit 1.2 DML&#xff08;数据修改语言&#xff09; 对数据表的增删改 insert into update set delete form 1.…

【JavaEE进阶】 #{}和${}

文章目录 &#x1f343;前言&#x1f333;#{}和${}使⽤&#x1f6a9;Interger类型的参数&#xff08;基础数据类型&#xff09;&#x1f388;使用#{}&#x1f388;使用${} &#x1f6a9;String类型的参数使用&#x1f388;#{}使用&#x1f388;${} &#x1f38d;#{}和${}区别&a…

C++:引用

目录 概念&#xff1a; 引用的使用格式&#xff1a; 引用特性&#xff1a; 常引用 使用场景&#xff1a; 1、做参数 二级指针时的取别名 一级指针取别名 一般函数取别名 2、做返回值 函数返回值的原理&#xff1a; 引用的返回值使用&#xff1a; 引用和指针的对比&…

Java Swing桌面项目打包成可执行jar

前言 最近有需求&#xff0c;将Swing项目打包为一个可执行的jar包&#xff0c;遇见了一些问题&#xff0c;参考AI助手&#xff0c;解决了遇到的问题&#xff0c;也有一些亲身实践体会&#xff0c;记录一下。开发环境IntelliJ IDEA&#xff0c;JDK8&#xff0c;用kotlin语言实现…

navicat连接postgresql、人大金仓等数据库报错

navicat连接postgresql、人大金仓数据库报错问题是一个偶现的问题&#xff0c;需要我们特别关注&#xff1a; 1、客户端连接人大金仓数据库 这里注意&#xff1a;navicat连接postgresql、人大金仓数据库时均选择postgresql类型&#xff0c;因为人大金仓数据库底层和psql数据库…

【第五天】蓝桥杯备战

1、金币 https://www.lanqiao.cn/problems/357/learning/ 解法&#xff1a;暴力 import java.util.Scanner; // 1:无需package // 2: 类名必须Main, 不可修改public class Main {public static void main(String[] args) {Scanner scan new Scanner(System.in);//在此输入…

01_Anaconda环境搭建

概述 Anaconda包含了许多常用的科学计算和数据分析的库和工具。通过Anaconda&#xff0c;用户可以更方便地安装、管理和更新这些库和工具&#xff0c;从而提高工作效率。 Anaconda还提供了一个名为conda的包管理器&#xff0c;可以帮助用户方便地安装、管理和更新这些库和工具…

写静态页面——魅族声学_前端页面练习

1、效果: 1、html代码: <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>魅族声学</titl…

金智易表通构建学生缴费数据查询+帆软构建缴费大数据报表并整合到微服务

使用金智易表通挂接外部数据,快速建设查询类服务,本次构建学生欠费数据查询,共有3块设计,规划如下: 1、欠费明细查询:学校领导和财务处等部门可查询全校欠费学生明细数据;各二级学院教职工可查询本二级学院欠费学生明细数据。 2、大数据统计报表:从应收总额、欠费总额…

Spring与Redis集成

1.引入RedisTemplate 据以前的情况&#xff0c;我们在Java中使用Redis时一般是使用Jedis来操作的&#xff0c;大致的一段代码如下所示 Overridepublic User findUserById(Integer id) {User user null;Jedis jedis null;try {jedis jedisPool.getResource();String userStr…

直接在GitHub上使用vscode阅读源码

方法&#xff1a; 直接在github后面输入1s即可 效果&#xff1a;

光学系统的核心--分辨率

前言 在机器视觉领域&#xff0c;可以把各个部件划分为光源&#xff0c;镜头&#xff0c;相机&#xff0c;采集卡&#xff0c;算法&#xff0c;运动平台等。各个部件都是系统的有机组合&#xff0c;均有各自的重要性。在实际应用中&#xff0c;成像镜头涉及的光学理论较多&…

[数据结构]-哈希

前言 作者&#xff1a;小蜗牛向前冲 名言&#xff1a;我可以接受失败&#xff0c;但我不能接受放弃 如果觉的博主的文章还不错的话&#xff0c;还请点赞&#xff0c;收藏&#xff0c;关注&#x1f440;支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 本期学习目标&…

智能工厂4G无线设备预测维护云端联动的DI、AI、DO混合信号处理单元

在现代工业智能化进程中&#xff0c;一款集成了丰富I/O接口并能与各大云平台无缝对接的智能设备显得尤为重要。比如最近推出的这款创新产品&#xff0c;它集合了8路数字输入通道&#xff0c;涵盖了干湿节点的识别功能&#xff0c;适用于多种开关量信号的读取&#xff1b;同时&a…

(八)springboot实战——springboot3下的webflux项目全局异常处理

前言 在webflux响应式编程中&#xff0c;如何处理系统运行时异常是本节的主要内容。在传统的Servlet阻塞式web项目中主要通过HandlerExceptionResolver处理器来处理&#xff0c;而在webflux响应式web项目中&#xff0c;则是通过DispatchExceptionHandler异常处理器来处理异常。…

[SWPUCTF 2018]SimplePHP1

打开环境 有查看文件跟上传文件&#xff0c;查看文件里面显示没有文件url貌似可以文件读取 上传文件里面可以上传文件。 先看一下可不可以文件读取 /etc/passwd不能读取&#xff0c;源码提示flag在f1ag.php 看看能不能读取当前的文件&#xff0c; 先把代码摘下来 file.php …

JavaScript 之 作用域变量提升闭包

一、JavaScript 代码的执行 浏览器内核是由两部分组成的&#xff0c;以 webkit 为例 WebCore&#xff1a;负责HTML解析、布局、渲染等等相关的工作JavaScriptCore&#xff1a;解析、执行 JavaScript 代码 另外一个强大的 JavaScript 引擎就是 V8 引擎 二、深入 V8 引擎原理 …