1. 输入输出流相关的类
- istream 是用于输入的流类, cin 就是该类的对象。
- ostream 是用于输出的流类, cout 就是该类的对象。
- ifstream 是用于从文件读取数据的类。
- ofstream 是用于向文件写入数据的类。
- iostream 是既能用于输入,又能用于输出的类。
- fstream 是既能从文件读取数据,又能向文件写入数据的类。
- 输入流对象:cin 与标准输入设备相连,对应于标准输入流。用于从键盘读取数据,也可以被重定向为从文件中读取数据。
- 输出流对象:cout 与标准输出设备相连,对应于标准输出流。用于向屏幕输出数据,也可以被重定向为向文件写入数据。
cerr 与标准错误输出设备相连,对应于标准错误输出流,用于向屏幕输出出错信息。
clog 与标准错误输出设备相连 ,对应于标准错误输出流,用于向屏幕输出出错信息。
缺省情况下:(三者一样)
cerr << "Hello World!" << endl;
clog << "Hello World!" << endl;
cout << "Hello World!" << endl;
输出流重定向:
#include <iostream>
using namespace std;
int main()
{
int x,y;
cin >> x >> y;
freopen("test.txt","w",stdout); //将标准输出重定向到 test.txt 文件
if( y==0 ) //除数为0则在屏幕上输出错误信息
cerr << "errer" <<endl;
else
cout << x/y; //输出结果到 test.txt
system("pause");
return 0;
}
输入流重定向:
int main()
{
double f;
int n;
freopen("t.txt","r",stdin); //cin 被改为从 t.txt 中读取数据
cin >> f >>n;
cout << f << "," << n << endl;
system("pause");
return 0;
}
istream 类的成员函数:
istream & getline(char * buf, int bufsize);
该函数从输入流中读取 bufsize-1 个字符到缓冲区 buf ,或读到 ‘\n’ 为止(哪个先到算哪个)。
istream & getline(char * buf, int bufsize, char delim);
该函数从输入流中读取 bufsize-1 个字符到缓冲区 buf ,或读到 delim 字符为止(哪个先到算哪个)。
两个函数都会自动在 buf 中读入数据的结尾添加 '\0' 。'\n' 或 delim 都不会被读入 buf ,但会被从输入流中取走。
可以用 if( !cin.getline(...) ) 判断输入是否结束。
#include <iostream>
using namespace std;
int main()
{
int x;
char buf[100];
cin >> x;
cin.getline(buf,90);
cout << buf <<endl;
system("pause");
return 0;
}
2. 流操纵算子
- 整数流的基数:流操纵算子 dec(十进制), oct(八进制), hex(十六进制), setbase(任意进制)
- 浮点数的精度(precision, setprecision)
- 设置域宽(setw, width)
- 用户自定义的流操纵算子
使用流操纵算子需要 #include <iomanip>
1 整数流的基数
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
int n = 10;
cout << n << endl;
cout << hex << n <<endl; //十六进制
cout << dec << n <<endl; //十进制
cout << oct << n <<endl; //八进制
system("pause");
return 0;
}
2 控制浮点数精度的流操纵算子
- precision 是成员函数,其调用方式为:
cout.precision(5);
- setprecision 是流操作算子,其调用方式为:
cout << setprecision(5); //可以连续输出
它们的功能相同。指定输出浮点数的有效位数(非定点方式输出时)。指定输出浮点数小数点后的有效位数(定点方式输出时)。定点方式:小数点必须出现在个位数后面。
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
double x = 1234567.89,y = 12.34567;
int n = 1234567;
int m = 12;
cout << setprecision(6) << x <<endl << y << endl << n << endl << m;
//浮点数输出最多6位有效数字(缺省情况下为非定点方式输出)
system("pause");
return 0;
}
//输出: 1.23457e+006
12.3457
1234567 (整数不受精度影响)
12
设置和取消以小数点固定位置方式(定点方式)输出的代码:
cout << setiosflags(ios::fixed);
cout << resetiosflags(ios::fixed);
cout << setiosflags(ios::fixed) << setprecision(6) << x <<endl << y << endl << n << endl << m;
//输出 :1234567.890000
12.345670
1234567
12
3 设置域宽的流操纵算子
setw 是流操作算子,width 是成员函数。
cin >> setw(4);
cin.width(5);
cout << setw(4);
cout.width(5);
宽度设置有效性是一次性的,在每次读入和输出之前都要设置宽度。
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
int w = 4;
char string[10];
cin.width(5); //读入域宽时包含 '\0'
while(cin>>string)
{
cout.width(w++); //输出时域宽不包含 '\0'。字符不够时在前面补空格
cout<<string<<endl;
cin.width(5);
}
system("pause");
return 0;
}
//输出:1234567890
1234
5678 //字符不够时在前面补空格
90
3. 文件读写
1 创建文件
#include <fstream> //包含头文件
ofstream outFile("clients.dat",ios::out|ios::binary);
- "clients.dat" 要创建的文件的名字
- ios::out 文件打开方式
- ios::out 输出到文件,删除原因内容
- ios::app 输出到文件,保留原有内容,总是在尾部添加
- ios::binary 以二进制文件格式打开文件
也可以先创建 ofstream 对象,再用 open 函数打开:
ofstream fout;
fout.open("test.out",ios::out|ios::binary);
判断打开是否成功:
if (!fout)
{
cout << "File open error!" << endl;
}
文件名可以给出绝对路径,也可以给相对路径。没有交代路径信息,就是在当前文件夹下找文件。
2 字符文件读写
写一个程序,将文件 in.txt 里面的整数排序后,输出到 out.txt
例如:若 in.txt 的内容为:1 234 9 45 6 879
则执行本程序后。生成的 out.txt 的内容为:1 6 9 45 234 879
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
vector<int> v;
ifstream srcFile("in.txt",ios::in);
ofstream destFile("out.txt",ios::out);
int x;
while( srcFile >> x ) //ifstream 是 istream 的派生类,istream 有的操作 ifstream 也有
v.push_back(x);
sort(v.begin(),v.end());
for (int i=0;i<v.size();i++)
{
destFile << v[i] << " "; //ofstream 是 ostream 的派生类,ostream 有的操作 ofstream 也有
}
destFile.close();
srcFile.close();
system("pause");
return 0;
}
3 二进制文件读写
- 二进制读文件
ifstream 和 fstream 的成员函数:
istream & read(char *s, long n);
将文件读指针指向的地方的 n 个字节内容,读入到内存地址 s ,然后将文件读指针向后移动 n 字节(以 ios::in 方式打开文件时,一开始文件读指针指向文件开头)。
- 二进制写文件
istream & write(const char* s, long n);
将内存地址 s 处的 n 个字节内容,写入到文件中写指针指向的位置,然后将文件写指针向后移动 n 字节(以 ios::out 方式打开文件时,文件写指针一开始指向文件开头,以 ios::app 方式打开文件时,文件写指针一开始指向文件尾部)。
在文件中写入和读取一个整数例程:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ofstream fout("some.dat",ios::out|ios::binary);
int x = 120;
fout.write((const char *)(&x),sizeof(int)); //x 的内存地址为 &x,是 int* 类型,而参数类型需为 const char* 类型。
fout.close();
ifstream fin("some.dat",ios::in|ios::binary);
int y;
fin.read((char *)(&y),sizeof(int));
fin.close();
cout << y <<endl;
system("pause");
return 0;
}
从键盘输入几个学生的姓名和成绩,并以二进制文件形式保存。
#include <iostream>
#include <fstream>
using namespace std;
struct Student
{
char name[20];
int score;
};
int main()
{
Student s;
ofstream OutFile("student.dat",ios::out|ios::binary);
while(cin >> s.name >> s.score)
OutFile.write((char *)(&s),sizeof(s)); //每个 s 占24字节
OutFile.close();
system("pause");
return 0;
}
将 student.dat 文件内容读出并显示:
struct Student
{
char name[20];
int score;
};
int main()
{
Student s;
ifstream inFile("student.dat",ios::in|ios::binary);
if (!inFile)
{
cout << "error" <<endl;
return 0;
}
while(inFile.read((char *)(&s),sizeof(s)))
{
int readedBytes = inFile.gcount(); //看刚才读了多少字节
cout << s.name << " " << s.score << endl;
}
inFile.close();
system("pause");
return 0;
}
4. 函数模板
1 函数模板的格式
template <class 类型参数1,class 类型参数2,...>
返回值类型 模板名(形参表)
{
函数体
}
template <class T>
void Swap(T & x,T & y)
{
T tmp = x;
x = y;
y = tmp;
}
int main()
{
int n = 1,m = 2;
Swap(n , m); //编译器自动生成 void Swap(int &,int &)函数
double f = 1.2,g = 2.3;
Swap(f,g); //编译器自动生成 void Swap(double &,double &)函数
// Swap(n,f); //error.匹配模板函数时,不进行类型自动转换
system("pause");
return 0;
}
- 函数模板中可以有不止一个类型参数。
- 函数模板可以重载,只要它们的形参表或类型参数表不同即可。
- 匹配模板函数时,不进行类型自动转换.
函数模板实例:Map
//函数模板实例:Map
template<class T,class Pred>
void Map(T s,T e,T x,Pred op) //s 起点位置,e 终点位置,op 变换,然后复制到起点为 x 的地方
{
for(; s != e; ++s,++x)
{
*x = op(*s);
}
}
int Cube(int x)
{
return x * x * x;
}
double Square(double x)
{
return x * x;
}
int a[5] = {1,2,3,4,5},b[5];
double d[5] = {1.1,2.1,3.1,4.1,5.1}, c[5];
int main()
{
Map(a,a+5,b,Square); //void Map(int * s,int * e,int * x,double (*op)(double)) //第四个参数是函数指针类型(返回值double,参数double)
for(int i=0;i<5;++i)
cout << b[i] <<",";
cout << endl;
Map(a,a+5,b,Cube);
for(int i=0;i<5;i++)
cout << b[i] << ",";
cout << endl;
Map(d,d+5,c,Square);
for(int i=0;i<5;i++)
cout << c[i] << ",";
cout << endl;
system("pause");
return 0;
}
5. 类模板
template <class 类型参数1,class 类型参数2,...>
(也可以)template <typename 类型参数1,typename 类型参数2,...>
//类型参数表
class 类模板名
{
成员函数和成员变量
};
类模板里成员函数的写法:
template <class 类型参数1,class 类型参数2,...> //类型参数表
返回值类型 类模板名<类型参数名列表>::成员函数名 (参数表)
{
......
}
用类模板定义对象的写法:
类模板名 <真实类型参数表> 对象名(构造函数实参表);
类模板实例:Pair类模板
//类模板实例:Pair类模板
template <class T1,class T2>
class Pair
{
public:
T1 key; //关键字
T2 value; //值
Pair(T1 k,T2 v):key(k),value(v) { };
bool operator < (const Pair<T1,T2> & p) const;
};
template<class T1,class T2>
bool Pair<T1,T2>::operator<(const Pair<T1,T2> & p) const
{//Pair 的成员函数 operator <
return key < p.key;
}
int main()
{
Pair<string,int> student("Tom",19);
//实例化出一个类 Pair<string,int>
cout << student.key << " " << student.value;
system("pause");
return 0;
}
- 同一个类模板的两个模板类是不兼容的。完全不相关。