一、基本概念
-
流概念:输入时,程序从输入流中抽取字节;输出时,程序将字节插入到输出流中;程序只检查字节流不需要知道其来自何方,如下图
-
缓冲区:其为程序与设备之间的中介内存块,显式刷新命令或缓冲区满了都会触发缓冲区刷新
二、cout语句
- 常规操作
const char *p = "字符串字面量"; // 缓冲区:运行到此处,都是加到缓冲区,屏幕不显示字符串 cout << "p指针指向的字符串是:"; // 打印字符串:传入字符串指针,屏幕仍不显示字符串 cout << p; // 刷新缓冲区: // endl加换行符,并刷新缓冲区,flush单纯刷新缓冲区 // 将缓冲区的字符串释放到默认输出流设备屏幕上 cout << endl;
- 格式化输出
#include <iostream> // set***方法用 #include <iomanip> // sqrt方法用 #include <cmath> using namespace std; int main() { double a = 123456.723456; // 默认显示位数:6位,其余四舍五入,显示123457 cout << a << endl; // 以下两个不重置不改变 // fixed:小数点计数法,scientific:科学计数法 // right:靠右对齐, 还有left,无居中 cout << fixed << right; // setw:设置宽度(小数点也算一位),一次性 // setfill:设置填充符号,不重置不改变 cout << setw(6) << setfill('$') << "root" << setw(7) << setfill('>') << "sqrt" // 虽然字符串超过宽度,但也不截取 << setw(8) << setfill('<') << "fourth root" << endl; double root; for (int n = 10; n <= 30; n += 10) { // double:强制类型转换赋给root root = sqrt(double(n)); cout << setw(6) << setfill('$') << n // setprecision:设置精度位3位,小数点后有三位,不重置不改变 << setw(7) << setfill('>') << setprecision(3) << root << setw(8) << setfill('<') << setprecision(4) << sqrt(root) // 重置填充为空 << setfill(' ') << endl; } cout << a << endl; }
- 输出
123457 $$root>>>sqrtfourth root $$$$10>>3.162<<1.7783 $$$$20>>4.472<<2.1147 $$$$30>>5.477<<2.3403 123456.7235
补充:<iostream>对应了char,<wiostream>对应了w_char
三、cin语句
3.1 常规输入
- 空白:cin以输入分隔符,且丢弃空白符,如果
a b\tc
,代表三次输入 - 代码示例
#include <iostream> using namespace std; int main() { int n; cout<< "请输入:"; // cin返回值:若为n不可接受数据,则返回false,但非法数据停在流中 while(cin>>n){ cout<< "输入的字符是:"<< n << endl; cout << "请输入:"; } // 流状态: // 1、非法输入ios_base::failbit被设置为1,fail()返回true // 2、到达末尾ios_base::eofbit被设置为1,eof()返回true // 3、其他 ios_base::badbit被设置为1,bad()返回true if(cin.fail()){ cout << "非法输入导致跳出循环"<< endl; // clear()函数清除流状态,加参数为不清除项 cin.clear(ios_base::failbit); // 此处清了个寂寞,failbit还是1 } // 完全清除流状态 cin.clear(); // ignore功能:将之前阻塞在流中的换行符清除,否则若之前输入的是11a, // 在clear函数运行后,a会传给下面cin // ignore参数解释:分隔符前要丢弃的字符数,分隔符 // ignore原型:istream & ignore(int = 1, int = EOF) cin.ignore(255,'\n'); cout<< "请输入:"; // 若没ignore,非法字符会直接传给n cin>> n; cout << n <<endl; return 0; }
3.2 c风格getline
- 行为:读取一行(包含
\n
),然后将换行符换成\0
,赋值给C风格字符串指针 - 输入行为
- 仅读到一个换行符:设置failbit,需
cin.clear();cin.ignore();
后面的cin才能正常 - 输入字符数>限制:设置failbit值,需
cin.clear();
,多余字符会直接赋值后续cin语句
- 仅读到一个换行符:设置failbit,需
- 原型参数解释:
getline(字符指针,可存储字符串长度(含末尾\0),[分隔符])
- 代码示例(string版见4.1)
#include <iostream> using namespace std; int main() { char ch[100] = {}; char ch_1[100] = {}; // 方法1:指定分隔符 // 原型:istream & getline(char *, int, char); // 若输入123x456x,则123赋值ch,456赋值下一条cin语句ch_1 cin.getline(ch, 5,'x'); cin.getline(ch_1, 5,'x'); cout<<ch<<endl; cout<<ch_1<<endl; cout<<"显示分隔"<<endl; // 详见 3.1 cin.ignore(255,'\n'); // 方法2:无分隔符(即默认‘\n’) // 原型:istream & getline(char *, int); // a、若输入123456,则1234赋值ch,空赋值下一条cin.getline语句ch_1 // b、若输入123换行456,则显示正常 cin.getline(ch, 5); // 若字符数超限:还有其他字符,设置failbit,所以此处无输入越过 cin.getline(ch_1, 5); cout<<ch<<endl; cout<<ch_1<<endl; cout<<"显示结束"<<endl; return 0; }
3.3 c风格get
- 原型:
- 不含分隔符:
istream & get(char *, int, char);
- 指定分隔符:
istream & get(char *, int);
- 不含分隔符:
- 输入行为
- 设置failbit
- 条件:没有读取到任何字符,包括换行符
- 例子:
cin.get(p,3);cin.get(m,3);
,第二个cin.fail()为true
- 特点:<限定值:正常赋值,>限定值:拆分赋值
- 设置failbit
- 与getline区别:get将换行符读入字符串,getline将换行符读入,但丢弃
3.4 读取单个字符
- 循环读入单个字符(C风格字符)
#include <iostream> using namespace std; int main() { char ch; cout<< "请猜测字母:"; // 只能读取一个英文字符,中文是两个字符,这里读取会乱码 // 注意与3.3区别,只有一个参数,且是字符变量(非指针) while(cin.get(ch)){ if (ch=='a'){ cout<<"选中了"<<endl; break; } cout<<"没选中"<<endl; cout<<"请猜测字母:"; // 下次输入前,清除输入流中的换行符 cin.ignore(); } cout<< "游戏结束"<<endl; return 0; }
四、文件
- C++文件打开模式
C++模式 含义 ios_base::in 只读, ifstream fin(filename);
默认打开模式ios_base::out 无则创建并写,有则清空再写, ofstream fin(filename);
的默认打开模式ios_base::out | ios_base::app 打开并在末尾追加写入 ios_base::in | ios_base::binary 以二进制模式打开写入 - 文件指针位置
// 头起算:指针指向fileObject的第 n+1 个字节(默认是 ios::beg) file.seekg( n ); // 当前位置起算:把文件的读指针从 fileObject 当前位置向后移n个字节,n正负均可 file.seekg( n, ios::cur ); // 尾起算:把文件的读指针从 fileObject 末尾为基点,移n个字节,n<=0 file.seekg( n, ios::end ); // 返回当前n值:file为fstream,istream int n = file.tellg(); // 返回当前n值:file为ofstream int n = file.tellp();
4.1 文件输出和读取
- 代码示例
#include <iostream> #include <string> // ofstream和ifstream #include <fstream> using namespace std; int main() { string filename; cout<< "请输入文件名:"; cin >> filename; // 清除末尾的换行符 cin.ignore(); // 等同于oftream fou; fou.open(filename.c_str(),ios_base::out); // ios_base::out可省略 ofstream fou(filename.c_str()); // 用于接收文件传入的行 string words; // getline函数写法是针对string对象的,此处fin等同cin while(getline(cin,words)&& words!="q") // 向文件写入,fou 等同 cout fou<<words<<endl; // 一定记得关闭文件,可用fou.is_open();判断文件是否是打开的 fou.close(); // 清空文件流状态,fou可以复用指向其他文件 fou.clear(); cout<< "---------此处以下是读取文件显示-------"<< endl; ifstream fin(filename.c_str()); // getline函数写法是针对string对象的,此处fin等同cin while (getline(fin,words)){ // 将读取的行打印到屏幕 cout << words<< endl; } // 文件流状态判断函数 // 返回:0 cout << fin.bad(); // 返回:1 cout<< fin.fail(); // 返回:1 cout<< fin.eof(); // 关闭文件 fin.close(); return 0; }
4.2 二进制文件读写
- 功能:感觉这个可以DIY配置文件、数据库
- 二进制格式文件:以二进制保存数据,速度更快,不需转换,紧凑准确。
- 特点:
- 文本方式打开:以txt方式打开是乱码
- 多次追加相同数据:都会存,但是提取时用第一个
- 多平台问题:平台(windows)只可用本平台生成的二进制文件,不可用其他平台的
- 代码示例
#include <iostream> #include <string> #include <fstream> using namespace std; // 输入的数据,二进制只接收数据,不接受方法 class Student{ private: string _name; int _age; double _height; public: explicit Student(const string &name="无名",int age=0,double height=0.0) : _name(name), _age(age), _height(height) {} void show()const{ cout<<"名字为:"<<_name<<endl; cout<<"年龄为:"<<_age<<endl; cout<<"身高为:"<<_height<<endl; } }; int main() { // 做数据准备 Student stu("小王",22,175.5); // 清空文件输出、二进制 fstream f("stu.dat", ios_base::out|ios_base::binary); if (f.is_open()){ cout<<"------以下为读取数据-------"<<endl; stu.show(); // 文件输出流用write函数: // 参数1:强制类型转换,参数2:内存中stu占用长度 f.write((char*)&stu,sizeof stu); cout<< "传输完毕"<<endl; } // 关闭文件 f.close(); // 清空流状态,为后面重新绑定输入流做准备 f.clear(); cout<<"------以下为读取数据-------"<<endl; // 输入、二进制文件 f.open("stu.dat",ios_base::in|ios_base::binary); if (f.is_open()){ // 文件输入流用read函数: // 参数1:强制类型转换,参数2:内存中stu使用字符串长度 f.read((char*)&stu,sizeof stu); // 测试是否读取正确 stu.show(); } // 关闭文件 f.close(); // 清空流状态,为后面重新绑定输入流做准备,末尾也可以不清 f.clear(); return 0; }