【C++课程学习】:C++中的IO流(istream,iostream,fstream,sstream)

【C++课程学习】:C++中的IO流(istream,iostream,fstream,sstream)

🎁个人主页:我们的五年

🔍系列专栏:C++课程学习

🎉欢迎大家点赞👍评论📝收藏⭐文章

C++学习笔记:

https://blog.ZEEKLOG.net/djdjiejsn/category_12682189.html

前言:

 在C语言中有各种IO流,控制台IO流,文件IO流。C++作为一门面向对象的语言,肯定是要自己封装IO流的。更加灵活,自定义类也可以重载输入输出流。

目录

1.C语言中的流

1.1控制台IO:

1.2输入,输出缓冲区:

1.3 流是什么:

2.C++的IO流

2.1说明:

2.2标准流(cin)的标志位:

2.3当出现类型不匹配出现输入流fail错误时,怎么处理?

3.C++的标准IO流:

3.1使用说明:

3.3注意事项:

3.4istream作为逻辑判断真假

4.C++文件IO流

5.stringstream流


1.C语言中的流

1.1控制台IO:

控制台(console)流有printf,scanf

scanf从标准输入设备读取数据,放到变量中
printf向标准输出设备中输出数据

1.2输入,输出缓冲区:

设计输入输出缓冲区的好处:

提高效率,直接将一个小部分整体IO,避免多次IO。IO是和外设打交道,是很浪费时间的。

●有了缓存区,IO的底层实现可以交给操作系统,我们要IO的数据,直接拷贝到缓冲区就行,剩下的交给操作系统,其他类似的缓冲区也是这样的原理。这样可以上次开发不要管IO这部分了,屏蔽这部分的差异,开发效率更高。

●还有一点就是,计算机本来没有‘行’的概念,缓冲区的大小,就可以定义为行的大小,从而可以向缓冲区写满就刷新(按行刷新)。

1.3 流是什么:

1.有序, 2.连续, 3.有方向

2.C++的IO流

2.1说明:

除了标准IO流,还有文件IO流,stringIO流,后面都讲一下,C++的IO流是一个庞大的体系。继承关系可见下面的图。

推荐C++语法查询的网站:https://www.cplusplus.com/

不是官方的网站,但是感觉挺好用,有什么忘记了的一查便知。

ios继承ios_base,箭头就表示继承。

可见标准IO,文件IO,stringIO,都是由istream,ostream继承来的。

2.2标准流(cin)的标志位:

goodbit为1时,表示输入流正常。
eofbit为1时,表示读到文件末尾。
failbit为1时,表示逻辑错误,轻微错误,可以恢复
badbit为1,表示读写错误,严重错误,不可回复

 上面的这四个标志位,iostat用的是位图的思想,某个比特位为1,就表示某种情况,所以他们要被一起设置的时候,用按位与|。

eofbit, failbit and badbit are member constants with implementation-defined values that can be combined (as if with the bitwise OR operator). goodbit is zero, indicating that none of the other bits is set.

当eofbit,failbit,badbit没有被设置的时候,goodbit被设置。

2.3当出现类型不匹配出现输入流fail错误时,怎么处理?

类型不匹配,failbit被设置,badbit时很严重的错误,进程直接没了。

一:先把三个错误都设置为0,goodbit就设置为1了,就能正常使用了。

通过clear,setstate函数进行设置。

stat函数:

void setstate (iostate state);

clear函数:

void clear (iostate state = goodbit);

我觉得这个clear更好,因为默认的参数就是goodbit。

二:把cin输入缓冲区里面的数据全部拿走。

避免再次输入错误。

整体代码:

    if (cin.fail())
    {
        //清理标志位
        cin.clear();
        //清理缓冲区
        getline(cin, s);
    }
#include <iostream> #include <string> using namespace std; int main() { int n; cin >> n; cout << n << endl; string s; if (cin.fail()) { //清理标志位 cin.clear(); //清理缓冲区 getline(cin, s); } cout << "11111111111111" << endl; cout << cin.good() << endl; cout << cin.fail() << endl; cout << cin.bad() << endl; cout << cin.eof() << endl; cout << "11111111111111" << endl; cin >> n; cout << n << endl; return 0; }

3.C++的标准IO流:

3.1使用说明:

标准输入(cin),标准输出(cout),标准错误(cerr),标准日志(clog)都是继承ios。

前一个是由istream来的,后面三个是ostream来的。

cin是从输入缓冲区读取,放入变量中。

cout,cerr,clog都是向显示器输出,这三个差不多,应用场景不一样。用法如下。

他们都在命名空std中,要不展开命名空间,要不每次用的时候,指明命名空间。

#include <iostream> using namespace std; int main() { int a; cin >> a; //标准输入 cout <<"cout:" << a << endl; //标准输出 cerr <<"cerr:" << a << endl; //标准错误 clog <<"clog:" << a << endl; //标准日志 return 0; }
// 单个元素循环输入
while(cin>>a)
{
    // ...
}
// 多个元素循环输入
while(c>>a>>b>>c)
{
    // ...
}
// 整行接收
while(cin>>str)
{
    // ...

3.3注意事项:

1.我们在用cin的时候,如果我们输错了,一定要在回车之前修改,回车以后就写入输入缓冲区了,就不能修改了。前面也说了流是有方向的,连续的,有方向的,所以输入流,要把前面的读完,才能读后面的。

2.输入的类型和提取的类型必须一样,否则出错,根据不同错误设置不同的bit位。

3.空格和换行可以作为数据之间的区分标志。

4.内置类型库中已经重载了,如果自定义类型要想使用,要重载operator<<,operator>>。

5.连续输出时,Ctrl+z结束,错误标志failbit被设置。

3.4istream作为逻辑判断真假

我们在连续输入的时候,cin>>n放在while里面,但是operator >>函数返回的istream&,istream为什么能作为真假进行判断呢?

其本质是istream又去调用了operator bool()

当流失败的时候,有错误标志的时候,返回false,流没有问题的时候,就返回true,就能进行真假判断了。

    //while(cin>>n)
    while ((cin>>n).operator bool())
    {

        //哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈

        //相信美好的事情即将发生
    }

4.C++文件IO流

包含的头文件:

#include <fstream>

文件的可区分为:二进制文件,文本文件。

●ifstream ifile(只输入用)

●ofstream ofile(只输出用)

●fstream iofile(既输入又输出用)

刚刚在写的时候,就打开同一个文件,用ifstream,ofstream同时打开同一个文件,就读不出来了,要对文件读写,得用fstream。BUG

还有就是打开文件设置的权限。

ios_base::binary|ios_base::in
int main() { //const string filename = "file.txt"; //ofstream out(filename); //int n = 1001; //out <<n; //out.close(); //int m; //ifstream in(filename); //in >> m; //cout << m; const string filename = "file.txt"; //用|将这个合并 fstream out(filename,ios_base::binary|ios_base::in); int n = 1001; out <<n; int m; ifstream in(filename, ios_base::binary | ios_base::in); in >> m; cout << m; return 0; }

1.使用文件流对象的成员函数打开一个磁盘文件,使得文件流对象和磁盘文件之间建立联系。

2.使用提取和插入运算符对文件进行读写操作,或使用成员函数进行读。

3.关闭文件。


5.stringstream流

这个流的主要用途是,把一系列的类型,转换为字符串。

C语言中的转字符串的函数有:

1.使用itoa()函数。

2.使用sprintf()函数。

这两个函数就是要先开空间,确定好空间的大小,不太好使用。
int main() { stringstream s; int a = 12134; string str; s << a; str=s.str(); cout << str; return 0; }
stringstreams在转换结尾时(即最后一个转换后),会将其内部状态设置为badbit,因此下一次转换是必须调用clear()将状态重置为goodbit才可以转换,但是clear()不会将stringstreams底层字符串清空掉 。

1.stringstream底层是维护了一个string对象保存。

2.对同一个流多次转换时,一定要clear()清理,才能正确转换,但是clear不会把底层的string对象清空。

3.可以用.str("")对string对象进行清空。

4.用.str()拿到底层的string对象里的对象。

Read more

改造红黑树实现封装 map/set:感受C++ 标准容器的精妙设计与底层实现

改造红黑树实现封装 map/set:感受C++ 标准容器的精妙设计与底层实现

容器map/set的底层是红黑树,这一篇详解红黑树如何封装实现map/set。 1.map/set设计的巧妙之处 map是key/value类型,set是key类型,两个冲突的参数类型,是如何由红黑树封装而成? 暴力思路:两个红黑树,一个kv,一个k。可是这样代码复用率极低,维护成本高。 源码思路:利用 键提取器——仿函数 提取kv、k的key,用一颗红黑树实现map,set C语言一般用函数指针,但是它十分麻烦,C++有了仿函数就很方便 接下来在红黑树基础上封装map和set 2.map和set的实现 2.1map和set的基本框架 + 原红黑树结构变化 map是key、value结构,set是key结构:  既然我们要用一个红黑树封装实现map和set,那传的参数就得通用: 原本是K,V结构,现在,要改成通用的,就用T吧 T根据需要,可选择传pair<K,

By Ne0inhk
第十六届蓝桥杯省赛(软件类真题)C/C++ 大学A组

第十六届蓝桥杯省赛(软件类真题)C/C++ 大学A组

大纲: A.寻找质数 B:黑白棋 题目&解析&代码 A题 题目解析 本题的目标是枚举质数并计数,直到数到第2025个。由于2025不算太大,第2025个质数大约在17000~18000之间,完全可以在合理时间内通过简单枚举得到。 解题步骤: 从2开始遍历每个整数,判断它是否是质数。 质数判断采用试除法:对于一个数n,只需检查从2到√n的所有整数是否能整除n。若存在能整除的数,则n不是质数;否则是质数。 每找到一个质数,计数器加1。 当计数器达到2025时,输出当前的质数并结束。 优化点: 除了2以外,偶数不可能是质数,因此可以跳过偶数判断(直接步进2)。 在isPrime函数中,可以先处理特殊情况(n<2返回false),然后单独判断偶数,再对奇数进行试除,步进也可以设为2。 C++ 参考代码 以下代码实现了上述算法,并输出第2025个质数。 cpp

By Ne0inhk
计算机Java毕设实战-基于springboot的留守儿童关爱网站首页展示、宣传新闻、志愿活动、爱心捐赠【完整源码+LW+部署说明+演示视频,全bao一条龙等】

计算机Java毕设实战-基于springboot的留守儿童关爱网站首页展示、宣传新闻、志愿活动、爱心捐赠【完整源码+LW+部署说明+演示视频,全bao一条龙等】

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围::小程序、SpringBoot、SSM、JSP、Vue、PHP、Java、python、爬虫、数据可视化、大数据、物联网、机器学习等设计与开发。 主要内容:免费开题报告、任务书、全bao定制+中期检查PPT、代码编写、🚢文编写和辅导、🚢文降重、长期答辩答疑辅导、一对一专业代码讲解辅导答辩、模拟答辩演练、和理解代码逻辑思路。 特色服务内容:答辩必过班 (全程一对一技术交流,帮助大家顺利完成答辩,小白必选) 全网粉丝50W+,累计帮助2000+完成优秀毕设 🍅文末获取源码🍅 感兴趣的可以先收藏起来,还有大家在毕设选题,

By Ne0inhk
C++ 运算符重载:自定义类型的运算扩展

C++ 运算符重载:自定义类型的运算扩展

C++ 运算符重载:自定义类型的运算扩展 💡 学习目标:掌握运算符重载的核心语法与规则,能够为自定义类型重载常用运算符,实现类对象的灵活运算。 💡 学习重点:运算符重载的基本形式、成员函数与全局函数重载的区别、常见运算符的重载实现、禁止重载的运算符。 一、运算符重载的概念与核心价值 ✅ 结论:运算符重载是 C++ 静态多态的重要体现,允许为自定义类型(如类、结构体)重新定义运算符的行为,让自定义对象可以像内置类型一样使用运算符。 运算符重载的核心价值: 1. 简化代码书写:用直观的运算符替代繁琐的成员函数调用,提升代码可读性 2. 统一操作风格:让自定义类型的运算逻辑与内置类型保持一致,降低学习和使用成本 3. 扩展类型功能:根据业务需求定制运算符的行为,满足自定义类型的运算需求 ⚠️ 注意事项:运算符重载不会改变运算符的优先级和结合性,也不会改变运算符的操作数个数。 二、运算符重载的基本语法 运算符重载的本质是函数重载,分为成员函数重载和全局函数重载两种形式。 2.1 成员函数重载语法 将运算符重载函数定义为类的成员函数,语法格式如下: class

By Ne0inhk