文件操作与模版(Week 7)
文件操作
数据的层次
-
位 bit
-
字节 byte
-
域/记录
-
//举例,学生记录 int ID; char name[10]; int age; int rank[10];
-
-
将所有记录顺序的写入一个文件,就是顺序文件
文件和流
- 顺序文件的本质是一个有限字符构成的顺序字符流
- C++标准库中,有ifstream,ofstream和fstream共3个类,用于文件操作,统称为文件流类
文件操作
- 使用/创建文件的基本流程
- 打开文件
- 目的:通过指定文件名,建立文件和文件流对象的关联;指明文件的使用方式
- 读/写文件
- 利用读/写指针进行相应位置的操作
- 关闭文件
- 打开文件
建立顺序文件
#include <fstream> //包含头文件
ofstream outFile("client.dat",ios::out|ios::binary);//打开文件
- ofstream是fstream中定义的类
- outFile是自定义的ofstream类的对象
- 参数1:将要建立的文件的文件名
- 参数2:打开并建立文件的选项
- ios::out 输出到文件,删除原有内容
- ios:app 输出到文件,保留原有内容,总是在尾部添加
- ios::binary 以二进制文件格式打开文件
- 也可以先创建ofstream对象,再用open函数打开
ofstream fout;
fout.open("test.out",ios::out|ios::binary);
if(!fout){cerr<<"File open error!"<<endl;}//判断打开是否成功
- 文件名可以给出绝对路径,也可以给相对路径
- 没有交代路径信息,就是在当前文件夹下找文件
文件的读写指针
- 对于输入文件,有一个读指针
- 对于输出文件,有一个写指针
- 对于输入输出文件,有一个读写指针
- 标识文件操作的当前位置,该指针在哪里,读写操作就在哪里进行。
ofstream fout("a1.out",ios:app);
long location = fout.tellp(); //取得写指针的位置
location = 10L;
fout.seekp(location);//将写指针移动到第10个字节处
fout.seekp(location,ios::beg);//从头数location
fout.seekp(location,ios::cur);//从当前位置数location
fout.seekp(location,ios::end);//从尾部数location
//location可以为负
ifstream fin("a1.in",ios:in);
long location = fin.tellg(); //取得读指针的位置
location = 10L;
fin.seekg(location);//将读指针移动到第10个字节处
fin.seekg(location,ios::beg);//从头数location
fin.seekg(location,ios::cur);//从当前位置数location
fin.seekg(location,ios::end);//从尾部数location
//location可以为负
二进制文件读写
int x = 10;
fout.seekp(20,ios::beg);
fout.write((const char *)(&x),sizeof(int));
fin.seekg(0,ios::beg);
fin.read((char *)(&x),sizeof(int));
//二进制文件读写,直接写进二进制数据,记事本看未必正确
//下面的程序从键盘输入几个学生的姓名和成绩
//并以二进制文件形式存起来
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;
class CStudent{
public:
char szName[20];
int nScore;
};
int main()
{
CStudent s;
ofstream OutFile("c:\tmp\students.dat",ios::out|ios::binary);
while(cin>>s.szName>>s.nScore)
{
if(stricmp(s.szName,"exit") == 0) //名字为exit则结束
break;
OutFile.write((char*)&s,sizeof(s));
}
OutFile.close();
return 0;
}
- 文本文件/二进制文件打开文件的区别
- 在Unix/Linux下,二者一致,没有区别
- 在Windows下,文本文件是以"
"作为换行符
- 读出时,系统会将0x0d0a只读入0x0a
- 写入时,对于0x0a系统会自动写入0x0d
//下面程序将student.dat文件的内容读出并显示
#include <iostream>
#include <fstream>
using namespace std;
class CStudent
{
public:
char szName[20];
int nScore;
};
int main()
{
CStudent s;
ifstream inFile("students.dat",ios::in|ios::binary)
if(!inFile)
{
cout<<"error"<<endl;
return 0;
}
while(inFile.read((char*)&s,sizeof(s)))
{
int nReadedBytes = inFile.gcount();//看刚才读了多少字节
cout<<s.szName<<" "<<s.score<<endl;
}
inFile.close();
return 0;
}
//下面程序将student.dat文件的Jane的名字改成Mike
#include <iostream>
#include <fstream>
using namespace std;
class CStudent
{
public:
char szName[20];
int nScore;
};
int main()
{
CStudent s;
fstream iofile("c:\tmp\students.dat",ios::in|ios::out|ios::binary);
if(!iofile)
{
cout<<"error";
return 0;
}
iofile.seekp(2*sizeof(s),ios::beg);//定位写指针到第三个记录
iofile.write("Mike",strlen("Mike")+1);
iofile.seekg(0,ios::beg);//定位读指针到开头
while(iofile.read((char*)&s,sizeof(s)))
{
cout<<s.szName<<" "<<s.score<<endl;
}
iofile.close();
return 0;
}
显式关闭文件
-
if stream fin("test.dat",ios::in);
fin.close();
-
ofstream fout("test.dat",ios::out);
fout.close();
示例:mycopy程序,文件拷贝
//用法示例:
//mycopy src.dat dest.dat
//将src.dat拷贝到dest.dat
//如果dest.dat原来就有,则原来的文件会被覆盖
#include <iostream>
#include <fstream>
using namespace std;
int main(int argc, char* argv[])
{
if(argc != 3)
{
cout<<"File name missing!"<<endl;
return 0;
}
ifstream inFile(argv[1],ios::binary|ios::in);//打开文件用于读
if(!inFile)
{
cout<<"Source file open error."<<endl;
return 0;
}
ofstream outFile(argv[2],ios::binary|ios::out);//打开文件用于写
if(!outFile)
{
cout<<"New file open error."<<endl;
inFile.close();//打开的文件一定要关闭
return 0;
}
char c;
while(inFile.get(c)) //每次读取一个字符
outFile.put(c); //每次写入一个字符
outFile.close();
inFile.close();
return 0;
}
函数模版
泛型程序设计
- Generic Programming
- 算法实现时不指定具体要操作的数据的类型
- 泛型——算法实现一遍,即可适用于多种数据结构
- 优势:减少重复代码的编写
- 大量编写模版,使用模版的程序设计
- 函数模版
- 类模版
函数模版
- 为了交换两个int变量的值,需要编写如下Swap函数:
void Swap(int &x, int &y)
{
int tmp = x;
x = y;
y = tmp;
}
- 为了交换两个double型变量的值,还需要编写一个类似的Swap函数(虽然存在重载,可以使两个Swap函数同名,但是因为参数的类型不同,函数需要重写)
- 能否只写一个Swap,就能交换各种类型的变量?
- 用函数模版解决
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 &)函数
return 0;
}
- 函数模版可以有多个类型参数
- 求数组最大元素的MaxElement函数模版
template<Class T>
T MaxElement(T a[],int size)//size是数组元素个数
{
T tmpMax = a[0];
for(int i = 1;i < size;++i)
if(tmpMax < a[i])
tmpMax = a[i];
return tmpMax;
}
- 函数模版可以重载,只要它们的形参表不同即可
- C++编译器遵循以下优先顺序
- 先找参数完全匹配的普通函数(非由模版实例化而得的函数)
- 再找参数完全匹配的模版函数
- 再找实参经过自动类型转换后能够匹配的普通函数
- 都找不到则报错
- 避免赋值兼容原则引起函数模版中类型参数的二义性(T是int还是double),可以在函数模版中使用多个类型参数,可以避免二义性(T1时int,T2是double)
类模版
问题引入
- 想要定义一批相似的类
- 通过定义类模版,能够方便的生成不同的类
- 举例:
- 数组
- 一种常见的数据类型
- 元素可以是整数、学生、字符串……
- 考虑一个数组类
- 需要提供一些基本操作:查看数组长度(len),获取其中的一个元素(get),赋值其中的一个元素(set)
- 对于这些数组类,除了元素的类型不同之外,其他的完全相同
- 类模版
- 在定义类的时候给他一个/多个参数
- 这个/些参数表示不同的数据类型
- 数组
类模版的定义
- C++的类模版的写法如下:
template<类型参数表>
class 类模版名
{
成员函数和成员变量
};
- 类模版里的成员函数,如在类模版外面定义时
template<类型参数表>
返回值类型 类模版名<类型参数表>::成员函数名(参数表)
{
......
}
-
用类模版定义对象的写法如下:
类模版名 <类型参数表> 对象名(构造函数实际参数表);
-
如果类模版有无参构造函数,可以只写
类模版名 <真实类型参数表> 对象名;
-
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
{return key<p.key;}
- Pair类模版的使用
int main()
{
Pair<string,int> student("Tom",19);
//实例化出一个类Pair<string,int>
cout<<student.key<<" "<<student.value;
return 0;
}
使用类模版声明对象
- 编译器由类模版生成类的过程叫类模版的实例化
- 编译器自动用具体的数据类型,替换类模版中的类型参数,生成模版类的代码
- 由类模版实例化得到的类叫模版类
- 为类型参数指定的数据类型不同,得到的模版类也会不同
- 同一个类模版生成的两个模版类是不兼容的
函数模版作为类模版成员
#include <iostream>
using namespace std;
template <class T>
class A{
public:
template <class T2>
void Func(T2 t) {cout<<t;}//成员函数模版
};
int main(){
A<int> a;
a.Func('K');//成员函数模版Func被实例化
return 0;
}
类模版与非类型参数
-
类模版的参数声明中可以包括非类型参数
template <class T, int elementsNumber>
- 非类型参数:用来说明类模版中的属性
- 类型参数:用来说明类模版中的属性类型、成员操作的参数类型和返回值类型
类模版与继承
- 类模版派生出类模版
template<class T1, class T2>
class A{
T1 v1;T2 v2;
};
template<class T1, class T2>
class B:public A<T2,T1>{ //对于B的模版类来说,v1应该是T2类型,v2应该是T1类型
T1 v3;T2 v4;
};
template <class T>
class C:public B<T,T>{
T v5;
};
int main(){
B<int,double> obj1;
C<int> obj2;
return 0;
}
- 模版类(即类模版中类型/非类型参数实例化后的类)派生出类模版
template <class T1, class T2>
class A{T1 v1; T2 v2;};
template <class T>
class B:public A<int,double>{T v;}
int main()
{
B<char> obj1;
return 0;
}
//自动生成两个模版类:A<int, double>和B<char>
- 普通类派生出类模版
class A {int v1;};
template <class T>
class B: public A{ T v;};
int main(){
B<char> obj1;
return 0;
}
- 模版类派生出普通类
template <class T>
class A{ T v1; int n;};
class B:public A<int> {double v;};
int main(){
B obj1;
return 0;
}
string类
基本概念
- string类是一个模版类,它的定义如下
typedef basic_string<char> string;
- 使用string类要包含头文件<string>
初始化&赋值
- string对象的初始化
- string s1("Hello"); //一个参数的构造函数
- string s2(8,'x'); //两个参数的构造函数
- string month = "March";
- 注意:不提供以字符和整数为参数的构造函数
- 错误的初始化方法:
- string error1 = 'c';
- string error2('u');
- string error3 = 22;
- string error4(8);
- 错误的初始化方法:
- 但是可以将字符赋值给string对象
- string s; s = 'n';
长度&读取
- 若构造的string太长而无法表达,会抛出length_error异常
- string对象的长度用成员函数length()读取
string s("hello");
cout<<s.length()<<endl;
- string支持流读取运算符
string stringObject;
cin >> stringObject;
- string支持getline函数
string s;
getline(cin,s);
赋值&连接
- 用'='赋值
string s1("cat"),s2;
s2 = s1;
- 用assign成员函数复制
string s1("cat"),s3;
s3.assign(s1);
- 用assign成员函数部分复制
string s1("catpig"),s3;
s3.assign(s1,1,3);
//从s1中下标为1的字符开始复制3个字符给s3
- 单个字符复制
s2[5]=s1[3] = 'a';
- 逐个访问string对象中的字符
- 成员函数at会做范围检查,如果超出范围,会抛出out_of_range异常,而下标运算符不做范围检查
string s1("Hello");
for(int i=0; i<s1.length();i++)
cout<<s1.at(i)<<endl;
- 用+运算符连接字符串
string s1("good"),s2("morning!");
s1 += s2;
cout << s1;
- 用成员函数append连接字符串
string s1("good"),s2("morning!");
s1.append(s2);
cout << s1;
s2.append(s1,3,s1.size());//s1.size()为s1的字符数
cout << s2;
//下标为3开始,s1.size()个字符
//如果字符串内没有足够字符,则复制到字符串最后一个字符
比较string
- 用关系运算符比较string的大小
- == > >= < <= !=
- 返回值都是bool类型,成立返回true,否则返回false
string s1("hello"),s2("hello"),s3("hell");
bool b = (s1 == s2);
cout << b << endl;
b = (s1 == s3);
cout << b << endl;
b1 = (s1 > s3);
cout << b << endl;
子串
- 成员函数 substr()
string s1("hello world"),s2;
s2 = s1.substr(4,5);//下标4开始,5个字符
cout << s2 << endl;
寻找string中的字符
- 成员函数find()
string s1("hello world");
s1.find("lo");
//在s1中从前向后查找"lo"第一次出现的地方
//如果找到,返回"lo"开始的位置,即l所在的位置下标
//如果找不到,返回string::npos(string中定义的静态常量)
- 成员函数rfind()
string s1("hello world");
s1.rfind("lo");
//在s1中从后向前查找"lo"第一次出现的地方
//如果找到,返回"lo"开始的位置,即l所在的位置下标
//如果找不到,返回string::npos(string中定义的静态常量)
- 成员函数find_first_of()
string s1("hello world");
s1.find_first_of("abcd");
//在s1中从前向后查找"abcd“中任何一个字符第一次出现的地方
//如果找到,返回该字母的位置;如果找不到,返回string::npos
- 成员函数find_last_of()
string s1("hello world");
s1.find_last_of("abcd");
//在s1中从前向后查找"abcd“中任何一个字符最后一次出现的地方
//如果找到,返回该字母的位置;如果找不到,返回string::npos
- 成员函数find_first_not_of()
string s1("hello world");
s1.find_first_not_of("abcd");
//在s1中从前向后查找不在"abcd“中的字符第一次出现的地方
//如果找到,返回该字母的位置;如果找不到,返回string::npos
- 成员函数find_last_not_of()
string s1("hello world");
s1.find_last_not_of("abcd");
//在s1中从后向前查找不在"abcd“中的字符第一次出现的地方
//如果找到,返回该字母的位置;如果找不到,返回string::npos
替换string中的字符
- 成员函数erase()
string s1("hello worlld");
s1.erase(5);
cout << s1;
cout<<s1.length();
cout << s1.size();
//去掉下标5及之后的字符
- 成员函数find()
string s1("hello worlld");
cout << s1.find("ll",1) << endl;
cout << s1.find("ll",1) << endl;
cout << s1.find("ll",1) << endl;
//分别从下标1,2,3开始查找"ll"
- 成员函数replace()
string s1("hello world");
s1.replace(2,3,"haha");
cout << s1;
//将s1中下标2开始的3个字符换成"haha"
//输出:hehaha world
string s1("hello world");
s1.replace(2,3,"haha",1,2);
cout << s1;
//将s1中下标2开始的3个字符换成"haha"中下标1开始的2个字符
//输出:heah world
在string中插入字符
- 成员函数insert
string s1("hello world");
string s2("show insert");
s1.insert(5,s2);//将s2插入s1下标为5的位置
cout<<s1<<endl;
s1.insert(2,s2,5,3);//将s2中下标5开始的3个字符插入到s1下标2的位置
cout<<s1<<endl;
转换成C语言式char *字符串
- 成员函数c_str()
string s1("hello world");
printf("%s
",s1.c_str());
//s1.c_str()返回传统的const char *类型字符串
//且该字符串以' '结尾
输入与输出
与输入输出流操作相关的类
- istream是用于输入的流类,cin就是该类的对象
- ostream是用于输出的流类,cout就是该类的对象
- ifstream是用于从文件读取数据的类
- ofstream是用于向文件写入数据的类
- iostream是既能用于输入,又能用于输出的类
- fstream是既能从文件读取数据,又能向文件写入数据的类
标准流对象
-
输入流对象:
- cin:与标准输入设备相连
-
输出流对象:
- cout:与标准输出设备相连
- cerr:与标准错误输出设备相连
- clog:与标准错误输出设备相连
-
cin对应于标准输入流,用于从键盘读取数据,也可以被重定向为从文件中读取数据
-
cout对应于标准输出流,用于向屏幕输出数据,也可以被重定向为向文件写入数据
-
cerr对应于标准错误输出流,用于向屏幕输出出错信息
-
clog对应于标准错误输出流,用于向屏幕输出出错信息
-
cerr和clog的区别在于cerr不使用缓冲区,直接向显示器输出信息;而输出到clog中的信息先会被存放在缓冲区,缓冲区满或者刷新时才输出到屏幕
输出重定向
#include <iostream>
using namespace std;
int main(){
int x,y;
cin >> x >> y;
freopen("test.txt","w",stdout);//将标准输出重定向到test.txt文件,把stdout重定向到test.txt,w代表写
if(y == 0) //若除数为0则在屏幕上输出错误信息
cerr << "error." << endl;
else
cout<<x/y;//输出结果到test.txt
return 0;
}
输入重定向
#include <iostream>
using namespace std;
int main(){
double f;
int n;
freopen("t.txt","r",stdin);//cin被改为从t.txt中读取数据,r代表读
cin >> f >> n;
cout << f << "," << n << endl;
return 0;
}
判断输入流结束
可以用如下方法判断输入流结束
int x;
while(cin >> x){ //存在强制类型转换符的重载
...
}
return 0;
- 如果是从文件输入,比如前面有freopen("some.txt","r",stdin); 那么读到文件尾部,输入流就算结束
- 如果从键盘输入,则在单独一行输入Ctrl+Z代表输入流结束
istream类的成员函数
istream & getline(char * buf, int bufSize);
- 从输入流中读取bufSize-1个字符到缓冲区buf,或读到碰到' '为止(哪个先到算哪个)
istream & getline(char * buf, int bufSize, char delim);
-
从输入流中读取bufSize-1个字符到缓冲区buf,或读到碰到delim字符为止(哪个先到算哪个)
-
两个函数都会自动在buf中读取数据的结尾添加 。 ' '或delim都不会被读入buf,但会被从输入流中取走。如果输入流中' '或delim之前的字符个数达到或超过了bufSize个,就导致读入出错,其结果就是,虽然本次读入已经完成,但之后的读入就会失败了。
-
可以用if(!cin.getliine(...))判断输入是否结束
-
bool eof(); 判断输入流是否结束
-
int peek(); 返回下一个字符,但不从流中去掉
-
istream &putback(char c); 将字符ch放回输入流
-
istream &ignore(int nCount = 1, int delim = EOF); 从流中删掉最多nCount个字符,遇到EOF时结束
#include <iostream>
using namespace std;
int main(){
int x;
char buf[100];
cin >> x;
cin.getline(buf,90);
cout<<buf<<endl;
return 0;
}
练习题
Quiz 1
#include <iostream>
using namespace std;
// 在此处补充你的代码
template <class T>
class CArray3D{
private:
T *** _array;
int _r,_c,_l;
public:
CArray3D(int r,int c,int l)
{
_array = new T **[r];
for (int i = 0; i < r; i++) {
_array[i] = new T* [c];
}
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
_array[i][j] = new T[l];
}
}
_r = r; _c = c; _l = l;
}
T ** operator[] (int index)
{
return _array[index];
}
};
int main()
{
CArray3D<int> a(3,4,5);
int No = 0;
for( int i = 0; i < 3; ++ i )
for( int j = 0; j < 4; ++j )
for( int k = 0; k < 5; ++k )
a[i][j][k] = No ++;
for( int i = 0; i < 3; ++ i )
for( int j = 0; j < 4; ++j )
for( int k = 0; k < 5; ++k )
cout << a[i][j][k] << ",";
return 0;
}
Quiz 2
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
double a;
cin >> a;
cout << setiosflags(ios::fixed) << setprecision(5) << a << endl;
cout << scientific << setprecision(7) << a << endl;
}
Quiz 3
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
int a;
cin >> a;
cout << hex << a << endl;
cout << dec << setw(10) << setfill('0')<< a << endl;
}
Quiz 4
/**********************
author KINGRAIN@EECS_PKU
time June 10,2010
dorm
poj3430
给定n个字符串(从1开始编号),每个字符串中的字符位置从0开始编号,长度为1-500,现有如下若干操作:
copy N X L:取出第N个字符串第X个字符开始的长度为L的字符串。
add S1 S2:判断S1,S2是否为0-99999之间的整数,若是则将其转化为整数做加法,若不是,则作字符串加法,返回的值为一字符串。
find S N:在第N个字符串中从左开始找寻S字符串,返回其第一次出现的位置,若没有找到,返回字符串的长度。
rfind S N:在第N个字符串中从右开始找寻S字符串,返回其第一次出现的位置,若没有找到,返回字符串的长度。
insert S N X:在第N个字符串的第X个字符位置中插入S字符串。
reset S N:将第N个字符串变为S。
print N:打印输出第N个字符串。
printall:打印输出所有字符串。
over:结束操作。
其中N,X,L可由find与rfind操作表达式构成,S,S1,S2可由copy与add操作表达式构成。
***********************/
/**********************
解题心得
S1 S2可能大于99999
N X L 可能小于0
使用构造函数主要是受到大牛的影响 本来直接调用函数就行了…… 看起来比较高级,但其实有点麻烦
**********************/
#include <iostream>
#include <string>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
string str[22];
string commend;
int N;
inline string MyCopy(); // copy N X L:取出第N个字符串第X个字符开始的长度为L的字符串。
inline string MyAdd(); // add S1 S2:判断S1,S2是否为0-99999之间的整数,若是则将其转化为整数做加法,若不是,则作字符串加法,返回的值为一字符串。
inline int MyFind(); // find S N:在第N个字符串中从左开始找寻S字符串,返回其第一次出现的位置,若没有找到,返回字符串的长度。
inline int MyRfind(); // rfind S N:在第N个字符串中从右开始找寻S字符串,返回其第一次出现的位置,若没有找到,返回字符串的长度。
inline void MyInsert(); // insert S N X:在第N个字符串的第X个字符位置中插入S字符串。
inline void MyReset(); // reset S N:将第N个字符串变为S。
struct GETS
{
GETS(string &s) // 递归获得真正的s串
{//因为S可以是字符串、copy表达式、add表达式,所以此处需要分情况处理
cin >> s;
if (s=="copy")
s = MyCopy();
else if (s=="add")
s = MyAdd();
}
};
struct GETINT
{
string Commend;
GETINT(int &n) // 递归获得真正的int n
{//因为int型变量N,X,L可由整数、find与rfind操作表达式构成,所以此处要分情况处理
cin >> Commend;
if (Commend=="find")
n = MyFind();
else if (Commend=="rfind")
n = MyRfind();
else
n = atoi(Commend.c_str());
}
};
struct GETSTRING
{
GETSTRING(int &m, string &s) // 递归获得真正的s串 并判断其是否为整数
{
GETS Gets(s);
int i = 0;
for (m=0; i<s.length(); i++)
if ((s.at(i)>='0')&&(s.at(i)<='9'))
m = m * 10 + s.at(i)-'0';
else
break;
if ((i!=s.length())||(m>99999))
m = -1;
}
};
int main()
{
cin >> N;
for (int i=0; i<N; i++)
cin >> str[i+1];
while (cin >> commend)
{
if (commend=="over")
break;
switch(commend.at(1))
{
case 'n': MyInsert(); break;
case 'e': MyReset(); break;
case 'r': if (commend=="print")
{
int n;
cin >> n;
cout << str[n] << endl;
}
else
{
for (int j=1; j<=N; j++)
cout << str[j] << endl;
}
break;
}
}
return 0;
}
inline string MyCopy()
{
int n, x, l;
GETINT getintn(n);
GETINT getintx(x);
GETINT getintl(l);
return (str[n].substr(x,l));
}
inline string MyAdd() // add S1 S2:判断S1,S2是否为0-99999之间的整数,若是则将其转化为整数做加法,若不是,则作字符串加法,返回的值为一字符串。
{
string s1,s2;
int m=-1, n=-1;
GETSTRING getstringms1(m,s1);
GETSTRING getstringns2(n,s2);
if ((m==-1)||(n==-1))
return (s1+s2);
else
{
m += n;
char chars[8];
sprintf(chars,"%d",m);
return chars;
}
}
inline int MyFind() // find S N:在第N个字符串中从左开始找寻S字符串,返回其第一次出现的位置,若没有找到,返回 ?? 哪个 ?? 字符串的长度。
{
string s;
int n,value;
cin >> s;
GETINT getintn(n);
value = str[n].find(s);
if (value==string::npos)
value = str[n].length();
return value;
}
inline int MyRfind() // rfind S N:在第N个字符串中从右开始找寻S字符串,返回其第一次出现的位置,若没有找到,返回字符串的长度。
{
string s;
int n,value;
cin >> s;
GETINT getintn(n);
value = str[n].rfind(s);
if (value==string::npos)
value = str[n].length();
return value;
}
inline void MyInsert() // insert S N X:在第N个字符串的第X个字符位置中插入S字符串。
{
string s;
int n,x;
GETS Gets(s);
GETINT getintn(n);
GETINT getintx(x);
str[n].insert(x,s);
}
inline void MyReset() // reset S N:将第N个字符串变为S。
{
string s;
int n;
GETS Gets(s);
GETINT getintn(n);
str[n].assign(s);
}
//还是一道没思路的题,查的答案
//sprintf 最常见的应用之一莫过于把整数打印到字符串中,所以,spritnf 在大多数场合可以替代itoa
//如:把整数123 打印成一个字符串保存在s 中。
//sprintf(s, "%d", 123); 产生"123"