【C/C++】IO流

目录

前言:

一,C语言的I/O流

二,C++的I/O流

2-1,C++标准IO流

2-2,IO流的连续输入


前言:

        “流”即是流动的意思,是物质从一处向另一处流动的过程,是对一种有序连续且具有方向性的数据的抽象描述。I/O是指输入输出设备。C/C++的I/O流是指信息从外部输入设备(如键盘)向计算机内部(如内存)输入和从内存向外部输出设备(显示器)输出的过程。它的特性是有序连续性和方向性。


一,C语言的I/O流

        C语言中我们用到的最频繁的输入输出方式就是scanf()printf()scanf 从标准输入设备(键 盘)读取数据,并将值存放在变量中。printf 将指定的文字/字符串输出到标准输出设备(屏幕),注意宽度输出和精度输出控制。除此外C语言还提供了类似于fprintf、fscanf等等专门控制I/O的函数接口。C语言借助了相应的缓冲区来进行输入与输出(缓冲器的专门讲解:缓冲区),如下图所示:

  输入输出缓冲区优点:

        1,可以屏蔽掉低级I/O的实现,低级I/O的实现依赖操作系统本身内核的实现,所以如果能够屏蔽这部分的差异,可以很容易写出可移植的程序。

        2,减少因频繁地、小块地读写数据而产生的性能开销。这里的缓冲区可一次性存入这些数据,等到刷新缓冲区时将进行输入/输出。

        C语言对于I/O这块需注意缓冲区的刷新,我们来观看以下C语言的代码问题。

#include <stdio.h>
int main()
{
    char password[20] = { 0 };
    printf("请输入密码: ");
    scanf("%s", password);
    printf("请确认密码(Y/N): ");
    char input = 0;
    scanf("%c", &input);  //注意:这块开始出问题
    if (input == 'Y')
        printf("确认成功\n");
    else
        printf("确认失败\n");
    return 0;
}

        scanf 函数的原理就是行缓冲,即输入回车('\n')就会刷新缓冲区。不过需要注意,用户最后输入的回车也会储存在缓冲区。上面代码的问题就出现在scanf的行刷新,当输入完 password 并回车后,缓冲区中还存在回车这个残留字符,当再次进行input流操作时,缓冲区将其字符赋给input并自动刷新(因为缓冲区已经没有数据了),即input == '\n',就会出现上面那种情况。这里需要将缓冲区里面残留字符给去掉或使用 fflush强制刷新缓冲区,但 fflush在有些编译器是没有的,它不属于C标准,不推荐使用。

#include <stdio.h>
int main()
{
    char x = 0, y = 0;
    scanf("%c", &x);
    printf("x = %c\n", x);

    //将缓冲区中的'\n'拿出,即清理缓冲区,若需要清理大部分字符,这里要使用循环语句
    getchar(); 
    scanf("%c", &y);
    if (y == '\n')
        printf("y == \\n\n");
    else 
        printf("y = %c\n", y);    
    return 0;
}

输出一:没有getchar清理缓冲区字符

输出二:getchar清理缓冲区字符


二,C++的I/O流

2-1,C++标准IO流

        C++的I/O底层原理与C语言一样,但C++系统实现了一个庞大的类库来实现I/O流操作,其中ios为基类,其他类都是直接或间接派生自ios类。

        其中,istream(输入流)和ostream(输出流)是I/O(输入/输出)流类的重要组成部分,它们定义了进行I/O操作的基本接口。cin、cout、cerr、clog都是istreamostream的实例。这两个类及其派生类(如ifstreamofstream等)允许程序员以一种简洁且灵活的方式与各种数据源(如文件、控制台等)进行交互。

        istream(输入流)定义了从数据源(如文件、控制台等)读取数据的基本操作,它包含了一系列以 operator>>形式出现的成员函数,用于读取不同类型的数据。其中我们常用于从控制台读取数据的cin就是istream的一个实例,而cin只有把输入缓冲区中的数据取完后(即刷新缓冲区),才要求输入新的数据,补足了C语言的scanf的缺陷。

        ostream(输出流)定义了向数据目标(如文件、控制台等)写入数据的基本操作,它包含了一系列以 operator<<形式出现的成员函数,用于写入不同类型的数据。其中我们常用于向控制台写入数据的cout就是ostream的一个实例,而平常与cout连用的std::endl操作符不仅插入了一个换行符,还刷新了与std::cout关联的输出缓冲区。

        C++标准IO流除了cout标准输出和cin标准输入外,还有cerr用来进行标准错误的输出,以及clog进行日志的输出。从上图可以看出,cout、 cerr、clog是ostream类的三个不同的对象,因此这三个对象现在基本没有区别,只是应用场景不同,一般情况下cout用的比较多。

        C++的标准IO流之所以能够直接输出内置类型数据,是因为标准库已经将所有内置类型的输入和输出全部重载了。对于自定义类型,若需要支持cin和cout的标准输入输出,需要对 << 和 >>进行重载。

        总的来说,C++的IO流是使用面向对象+运算符重载的方式实现的,它识别类型的本质是函数重载,内置类型可以直接使用是因为库里面istream/ostream类型已经实现了,自定义类型则需要自己重载<< 和 >>,也就是说C++的这种IO模式能够更好的兼容自定义类型,流插入和流提取。

2-2,IO流的连续输入

        编程算法中有些情况会出现不断输入的情况,如:while (cin >> a){.....},结束输入的情况很多时候都是使用快捷键:Ctrl + c解决(Ctrl + c是向系统内部发送结束当前进程的信号,直接暴力杀死进程)。

        实际上我们看到使用while (cin >> a){.....}去流中提取对象数据时,调用的是operator>>,返回值是 istream类型的对象,即while(cin >> a)实际上是while (operator>>(cin, a)),那么这里可以做逻辑条件值,源自于istream的对象又调用了operator bool(),operator bool()调用时如果接收流失败或有结束标志时,则返回false。任何类型只要想判断,只用重载一个operator bool()即可。

class Date
{
    friend ostream& operator << (ostream& out, const Date& d);
    friend istream& operator >> (istream& in, Date& d);
public:
    Date(int year = 1, int month = 1, int day = 1)
        :_year(year)
        , _month(month)
        , _day(day)
    {}
    //重载bool类型,用于循环语句的判断

    operator bool() 
    {
        //这里假设输入_year为0时结束
        if (_year == 0)
            return false;
        else
            return true;
    }
private:
    int _year;
    int _month;
    int _day;
};
//实现Date类的流插入和流提取
istream& operator >> (istream& in, Date& d)
{
    in >> d._year >> d._month >> d._day;
    return in;
}
ostream& operator << (ostream& out, const Date& d)
{
    out << d._year << " " << d._month << " " << d._day;
    return out;
}
int main()
{
    Date d(2024, 6, 7);
    cout << "输出: " << d << endl;
    while (d)
    {
        cin >> d;
        cout << "输出: " << d << endl;
    }
    return 0;
}

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

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

相关文章

测试基础11:测试用例设计方法-等价类划分

课程大纲 1、概述 1.1测试用例设计方法意义 穷举测试&#xff1a;每种输入都测一次。最完备&#xff0c;但不现实。 使用设计方法&#xff0c;用最少的数据&#xff08;成本&#xff09;&#xff0c;实现最大的测试覆盖。 1.2常用设计方法 ①等价类划分 ②边界值分析 ③错误推…

Python采集东方财富网股票数据建立LSTM模型预测

Python采集东方财富网股票数据建立LSTM模型预测 一、数据爬取流程二、爬虫完整代码三、LSTM模型建模预测3.1 项目背景3.2 建模预测流程3.3 数据预处理3.4 数据可视化3.5 特征工程3.6 数据缩放3.7 数据转换3.8 模型创建3.9 评价模型3.10 可视化结果3.11 总结一、数据爬取流程 先…

运维开发(DevOps):加速软件交付的关键方法

1. 什么是运维开发 运维开发&#xff08;DevOps&#xff09;是将软件开发&#xff08;Development&#xff09;与信息技术运维&#xff08;Operations&#xff09;的流程整合在一起的实践方法。DevOps的目标是通过增强开发和运维团队之间的协作&#xff0c;提高软件产品的发布…

Linux路由设置

添加路由 一&#xff1a;使用 route 命令添加 使用route 命令添加的路由&#xff0c;机器重启或者网卡重启后路由就失效了&#xff0c;方法&#xff1a; //添加到主机的路由 # route add –host 192.168.1.11 dev eth0 # route add –host 192.168.1.12 gw 192.168.1.1 //添…

【计算机视觉】数字图像处理基础:以像素为单位的图像基本运算(点运算、代数运算、逻辑运算、几何运算、插值)

0、前言 在上篇文章中&#xff0c;我们对什么是数字图像、以及数字图像的组成&#xff08;离散的像素点&#xff09;进行了讲解&#x1f517;【计算机视觉】数字图像处理基础知识&#xff1a;模拟和数字图像、采样量化、像素的基本关系、灰度直方图、图像的分类。 我们知道&a…

【ARM Cache 与 MMU 系列文章 7.3 – ARMv8/v9 MMU 块描述符与页表描述符】

请阅读【ARM Cache 及 MMU/MPU 系列文章专栏导读】 及【嵌入式开发学习必备专栏】 上篇文章&#xff1a;【ARM Cache 系列文章 7.2 – ARMv8/v9 MMU 页表配置详细介绍 03 】 文章目录 MMU 块描述符与页描述符Block DescriptorBlock descriptor formatsBlock Entry 介绍Block En…

Linux驱动应用编程(四)IIC(获取BMP180温度/压力数据)

本文目录 一、基础1. 查看开发板手册&#xff0c;获取可用IIC总线2. 挂载从机&#xff0c;查看从机地址。3. 查看BMP180手册&#xff0c;使用命令读/写某寄存器值。4. 查看BMP180手册通信流程。 二、IIC常用API1. iic数据包/报2. ioctl函数 三、数据包如何被处理四、代码编写流…

transformers 阅读:BERT 模型

前言 想深入理解 BERT 模型&#xff0c;在阅读 transformers 库同时记录一下。 笔者小白&#xff0c;错误的地方请不吝指出。 Embedding 为了使 BERT 能处理大量下游任务&#xff0c;它的输入可以明确表示单一句子或句子对&#xff0c;例如<问题&#xff0c;答案>。 …

基本算法-枚举、模拟、递推(上)

目录 递归实现指数型枚举 题目描述 运行代码 代码思路 递归实现组合型枚举 题目描述 运行代码 代码思路 递归实现排列型枚举 题目描述 运行代码 代码思路 递归实现指数型枚举 题目描述 登录—专业IT笔试面试备考平台_牛客网 运行代码 #include<iostream> …

数据结构篇其六-串

数据结构—串 前置说明 由于学习Java面向对象语言走火入魔&#xff0c;试图在C语言中模拟实现面向对象设计。里面加入了大量的函数指针配合结构体来模拟类中的成员方法 故此篇&#xff0c;亦可称: 面向对象的C语言程序设计 用C语言实现串这种数据结构&#xff0c;并将它应用到…

运动会信息管理系统(Springboot+MySQL)

本课题旨在实现对运动会信息的全面管理&#xff0c;提供用户友好的界面和高效的操作体验。系统的基础功能包括运动员报名比赛、比赛成绩查询、资讯留言等。为了确保系统的高扩展性和稳定性&#xff0c;选用主流的开发技术&#xff0c;实现规范的项目结构和高效的性能。 技术选型…

算法—字符串操作

394. 字符串解码 - 力扣&#xff08;LeetCode&#xff09; class Solution { public:string longestCommonPrefix(vector<string>& strs) { string retstrs[0];//***1***记得先要初始化ret&#xff0c;作为第一个比较值for(int i0;i<strs.size();i){retfoundcom…

Zookeeper 详解:分布式协调服务的核心概念与实践

Zookeeper 详解&#xff1a;分布式协调服务的核心概念与实践 Apache Zookeeper 是一个分布式协调服务&#xff0c;广泛用于分布式应用程序的配置管理、服务发现、集群管理等。它提供了简单的分布式锁服务和命名服务&#xff0c;使开发者能够更加方便地构建高可靠性、高可用性的…

在 Windows 资源管理器中打开 FTP 站点终极解决方法 ftp打开方式更改为资源管理器

日常工作中&#xff0c;经常会用到FTP&#xff0c;一般情况下&#xff0c;FTP站点在IE中&#xff08;尤其是IE7以后版本&#xff09;打开&#xff0c;默认都不是以文件夹视图方式打开的&#xff0c;这时IE也会给你提示“若要在 Windows 资源管理器中查看此 FTP 站点&#xff0c…

Vue Router——hash模式和 history模式

在 Vue.js 中&#xff0c;Vue Router 是官方提供的路由管理器&#xff0c;它允许你以单页面应用&#xff08;SPA&#xff09;的方式构建你的Vue应用。Vue Router 支持两种路由模式&#xff1a;hash 模式和 history 模式。这两种模式的主要区别在于它们如何与浏览器的历史记录&a…

鸿蒙? 车载?Flutter? React Native? 为什么我劝你三思,说点不一样的

本文首发于公众号“AntDream”&#xff0c;欢迎微信搜索“AntDream”或扫描文章底部二维码关注&#xff0c;和我一起每天进步一点点 引言 当今信息技术领域日新月异&#xff0c;各种新技术和新平台层出不穷。鸿蒙&#xff08;HarmonyOS&#xff09;、Flutter、以及车载应用开发…

使用 Scapy 库编写 ICMP 不可达攻击脚本

一、介绍 ICMP不可达攻击是一种利用ICMP&#xff08;Internet Control Message Protocol&#xff09;不可达消息来干扰或中断目标系统的网络通信的攻击类型。通过发送伪造的ICMP不可达消息&#xff0c;攻击者可以诱使目标系统认为某些网络路径或主机不可达&#xff0c;从而导致…

前端开发高频面试题

好的&#xff0c;以下是对您提出的问题的详细回答&#xff1a; 说说vue动态权限绑定渲染列表&#xff08;权限列表渲染&#xff09; Vue中动态权限绑定渲染列表通常涉及以下步骤&#xff1a; 首先&#xff0c;通过API请求从服务器获取当前用户的权限数据。在Vue组件中&#xff…

《数据库原理与应用》

计算题 设有关系模式R(ABCDEF),F={ A→BC,CD→E,B→DA }1)求R的所有候选码。2)R最高属于第几范式 AE,BE 三个关系如下:教学管理系统包括下面3个表:Students (Sno, Sname, Sex, Birthday, Enrollyear, Speciality, Dno) Courses (Cno, Cname, Period, Credit) SC (…

二叉树及其在C语言中的实现A

一、引言 二叉树是数据结构中一种非常基础且重要的树形结构&#xff0c;它的每个节点最多有两个子节点&#xff0c;通常被称为左子节点和右子节点。二叉树在计算机科学中有着广泛的应用&#xff0c;如搜索、排序、存储数据等。本文将详细介绍二叉树的基本概念、特性以及在C语言…