day6补 cpp:c++输入输出流,流的四种状态,标准输入输出流
1.c++输入输出流
输入输出的含义:在编程语言中,程序的输入指从输入文件将数据传送给程序(内存),程序的输出指从程序(内存)将数据传送给输出文件
c++输入输出流机制:c++的i/o发生在流中,流是字节序列,字节流从设备(如键盘,磁盘驱动器,网络连接等)流向内存,这叫做输入操作,如果字节流从内存流向设备(如显示屏,打印机,磁盘驱动器,网络连接),这叫做输出操作。程序只关心是否正确输出了字节数据和读取了字节数据
c++常用流类型
1.对系统指定的标准设备的输入和输出。即从键盘输入数据到内存,从内存输出到显示器屏幕。这种输入输出称为标准的输入输出,简称标准io
2.以外村磁盘文件为对象进行输入和输出,即从磁盘文件输入数据到内存,从内存将数据输出到磁盘文件,以外存为对象的输入输出称为文件的输入输出,简称文件io
3.对内存中指定的空间进行输入输出,通常指定一个字符数组作为存储空间(实际上可以利用该空间存储任何信息),这种输入和输出称为字符串输入输出,简称串io
注:标准io使用了通用iio,它没有自己单独的io
2.流的四种状态 (重点)
通过流的状态函数实现:
bool good() const //流是goodbit状态,返回true,否则返回false
bool bad() const
bool eof() const
bool fail() const
3.标准输入输出流
标准输入流cin
istream
的定义位置
istream
是 C++ 标准输入流基类,定义在标准库头文件<istream>
中,并直接位于std
命名空间内。例如:
namespace std {
typedef basic_istream<char> istream; // 实际为basic_istream的别名
class istream{
public:
void clear(..){...}
istream& ignore(..){... return *this}
}
istream cin=。。。;//cin是istream类的一个实例
}功能与继承关系
istream
是输入流操作的基类,支持>>
运算符重载,用于从数据源(如键盘、文件)读取数据。- 它派生出其他输入流类:
ifstream
(文件输入流)istringstream
(字符串输入流)。与
std::cin
的关系
std::cin
是istream
类的全局对象实例,专门处理标准输入(键盘输入)。例如:
int x; std::cin >> x; // 调用istream::operator>>()
#include<iostream>
using std::istream;
using std::cin;
using std::cout;
using std::endl;
void printStreamStatus(istream & is){cout<<"is goodbit"<<is.good()<<endl;cout<<"is badbit"<<is.badbit()<<endl;cout<<"is failbit"<<is.failbit()<<endl;cout<<"is eofbit"<<is.eofbit()<<endl;
}
void test0(){printStreamStatus(cin); //1 0 0 0---输入流正常工作int num=10;cin>>num;cout<<"num:"<<num<<endl; printStreamStatus(cin);//若输入的是正确的数字1 0 0 0 若输入其他0 0 1 0---可恢复的错误,然后中止执行int num1=10;cin>>num1;cout<<"num1:"<<num1<<endl; printStreamStatus(cin);//若输入完正确的数字后,不按回车而是ctrl+d 0 0 0 1---跳转到流结尾
}
注意;除了goodbit状态可以连续进行下一输入,其他状态后直接退出
cin.clear()和cin.ignore()
cin.clear()恢复流状态,cin.ignore()舍弃上次输出
如果只cin.clear() 0
void printStreamStatus(istream & is){cout<<"is goodbit"<<is.good()<<endl;cout<<"is badbit"<<is.badbit()<<endl;cout<<"is failbit"<<is.failbit()<<endl;cout<<"is eofbit"<<is.eofbit()<<endl;
}
void test0(){printStreamStatus(cin);int num=10;cin>>nnum;cout<<"num="<<num<<endl;printStreamStatus(cin);//如经过了第一次的输入,使得标准输入流进入failbit/eofbit状态//希望能够恢复流的状态if(!cin.good()){cin.clear();//恢复流的状态--1 0 0 0 //还要清空缓冲区的内容cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');//系统最大值,max()是类numeric_limits<std::streamsize>的静态成员函数}string line;cin>>line;cout<<"line="<<line<<endl;printStreamStatus(cin);}
std::numeric_limits<std::streamsize>::max()是系统最大值,max()是类numeric_limits<std::streamsize>的静态成员函数,遇到字符‘\n’之前全部释放,包括此字符'\n'都清空
若不释放全部,会导致cin.clear()恢复1 0 0 0后,下次cin不会让你输入而是直接沿用上次未用cin.ignore()清除的的输入
#include<iostream>
#include<limits>
using namespace std;
void InputInt(int &number){cout<<"请输入一个int型的数据"<<endl;cin>>number;while(!cin.eof()){if(cin.bad()){return ;}else if(cin.fail()){cin.clear();cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');cout<<"请输入一个int型的数据"<<endkl;cin>>number;}else{cout<<"num:"<<number<<endl;break;}}
}
输入8.9可以取8,输入89you可以取89
4.作业
1.
注意:char *str没有初始化,是野指针。
2.实现一个自定义的String类
class String {
public:String() :_pstr(new char[1]())//不要:_pstr(nullptr)因为cout对于char*有重载功能,若_pstr初始化为空指针,cout会输出中断,除非先做个if(_pstr)判断{}String(const char* pstr) :_pstr(new char[strlen(pstr)+1]()){strcpy(_pstr, pstr);}String(const String& rhs):_pstr(new char[strlen(rhs._pstr)+1]()){strcpy(_pstr, rhs._pstr);}String& operator=(const String& rhs) {if (this != &rhs) {delete[] _pstr;_pstr = new char[strlen(rhs._pstr) + 1]();strcpy(_pstr, rhs._pstr);}return *this;}~String() {if (_pstr) {delete[] _pstr;_pstr = nullptr;}}void print() {cout << _pstr << endl;}size_t length() const{//const表示不会修改成员变量size_t len = 0;char* s = _pstr;while (*_pstr != '\0') {len++;s++;}return len;}const char* c_str() const {return _pstr;}
private:char* _pstr;
};
3.创建存放Point对象的vector,并进行遍历
class Point {
public:......
private:int _x;int _y;
};
void test() {vector<Point> v{{3,0},{4,0}}vector<Point> v{3,4};//共两个,分别是Point(3,0) Point(4,0)for (auto& ele : v) {cout << ele.print() << endl;}
}
注意:Point pt1(3,0);Point pt2(4,0);vector<Point>{pt1,pt2}
//因为Point pt1,pt2 是在栈区上创建,但vector<....>的对象必须在堆区,所以vector<Point>{pt1,pt2}中进行了拷贝构造
Point(1,2)调用构造函数Point(int,int)
然后将Point(1,2)调用拷贝构造函数到push_back()
销毁栈中Point(1,2)临时对象,每个都调用一个~Point()
然后在销毁vec时要先调用析构~Point(),销毁内的每个Point元素
4.创建存放int数据的vector的vector,尝试进行遍历,并体会vector对象和元素的存储位置
5.当流失效时,如何重置流的状态,并重新再正常使用流呢?
if(!cin.good()){cin.clear();cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
}