Mystring类!!!(对字符串来次大复习)

Experiment topic 2

自定义字符串类示例程序:

#include<iostream>
using namespace std;
const int n=256;
class mystring{
	char str[n];        //存放字符串的数组容器,可考虑定义指针,在构造函数中动态分配空间
	int maxsize;        //最大可用元素数,可防止数组出界,提高健壮性
	int last;           //已用元素最大下标
public:
	mystring(){
		last=-1;
		maxsize=n;
		str[0]='\0';
		cout<<"缺省构造函数"<<endl;
	}
	mystring(const char *s){//当C字符串过长,初始化时采用截尾处理
		last=-1;
		maxsize=n;
		do{
			last++;
			str[last]=s[last];
		}while(s[last]!='\0'&&last<maxsize-1);
		str[last] ='\0'; //截尾处理时,必须加串结束符
		cout<<"构造函数"<<endl;
	}
	mystring(const mystring & ms){ //devC++下不加const有问题?
		last=-1;
		maxsize=n;
		do{
			last++;
			str[last]=ms.str[last];
		}while(last<ms.last);
		cout<<"拷贝构造函数"<<endl;
	}
	~mystring(){
		cout<<"析构函数"<<endl;
	}
	void show(){//如需重载<<,则参考补充课件,替代方法是用show()函数
		cout<<str<<endl;
	}
	int strlen(){return last;}; //求字符串长度
	void reverse();             //逆置字符串
	int strchr(char c);         //查找字符串中字符c首次出现的位置 
	int strstr (mystring str1); //查找主串中子串str1首次出现的位置
	char & operator[](int i){   //返回引用,可读可写
		if(i>last) last=i;  //下标运算符,可添加长度但不查边界
		return str[i];
	}
	mystring & operator=(const mystring &);
	mystring & operator=(const char * ms);//这里重载的=是把C风格字符串赋给mystring
	mystring operator+( mystring &); //这里返回不能用引用
	mystring & operator+=( mystring &);
	bool operator<( mystring &);
	bool operator==( mystring &);
};
void mystring::reverse(){     
	int i=0,j=last-1;
	char temp;
	while(j>i){//注意此处,从串两头同时向中间移动,重合或交错时停止
		temp=str[i]; //头尾交换
		str[i]=str[j];
		str[j]=temp;
		i++;
		j--;
	}
}
int mystring::strchr(char c){
	int i;
	for(i=0;i!=last;i++) if(str[i]==c) return i;
	return -1; //未找到返回-1
}
int mystring::strstr(mystring str1){
	int i=0,k=1;
	while(str[i]!='\0'){//只要主串还有字符未查,则继续
		while(str[i]!=str1[0]&&str[i]!='\0') i++;
//找到主串含有子串的第一个字符,或主串查完停止
		if(str[i]!='\0'){//核对子串其他字符
			while(str[i+k]==str1.str[k]&&k<str1.last) k++;//字符串结束符不比较
			if(k==str1.last) return i;//找到子串返回
			k=1;
			i++;
		}
	}
	return -1; //未找到返回-1
}
mystring & mystring::operator=(const mystring & ms){//这里返回值改为引用,不调用拷贝构造函数
	last=-1;	
	do{
		last++;
		str[last]=ms.str[last];
	}while(last<ms.last);
	return *this;
}
mystring & mystring::operator=(const char* ms){ //这里返回值为引用,不调用拷贝构造函数
	last=-1;	
	do{
		last++;
		str[last]=ms[last];
	}while(ms[last]!='\0'&&last<maxsize-1);
	str[last] ='\0'; //截尾处理时,必须加串结束符
	return *this;
}
mystring mystring::operator+( mystring & ms){//注意+和+=的不同
	mystring temp(*this);//+必须在一份拷贝上进行
	int i=-1;
	temp.last--;//串的结尾是结束符,连接时要覆盖掉
	do{
		temp.last++;
		i++;
		temp.str[temp.last]=ms.str[i];
	}while(i<ms.last&& temp.last<maxsize-1);	
	temp.str[temp.last] ='\0'; //截尾处理时,必须加串结束符
	return temp;//拷贝的临时变量生命期在调用它的表达式中
}
mystring & mystring::operator+=( mystring & ms){//+=在对象自身进行
	int i=-1;
	last--;//串的结尾是结束符,连接时要覆盖掉
	do{
		last++;
		i++;
		str[last]=ms.str[i];
	}while(i<ms.last&&last<maxsize-1);
	str[last] ='\0'; //截尾处理时,必须加串结束符
	return *this;
}//这里返回值改为引用,不调用拷贝构造函数
bool mystring::operator<( mystring & ms){   //重载<运算符
	int i=0,k;
	do{
		k=str[i]-ms.str[i];
		i++;
	}while(k==0&&i<last&&i<ms.last);
	if(k<0) return true;
	if(i==last&&i!=ms.last) return true;
	return false;
}
bool mystring::operator==( mystring & ms){
	int i=0,k;
	if(last!=ms.last) return false;
	do{
		k=str[i]-ms.str[i];
		i++;
	}while(k==0&&i<last);
	if(k!=0) return false;
	else return true;
}
int main(){
	int i;
	char *sp1="中国民航大学",*sp2="交通学院",*sp3="学生",*sp4="教师";
	mystring ms1(sp1),ms2(sp2),ms3(sp3);//ms1,ms2,ms3是用构造函数生成
	mystring ms4(ms3),ms5=ms3,ms6; //ms4,ms5用拷贝构造函数生成;ms6用缺省构造函数
	ms6=sp4; //ms6赋值是返回引用,不用拷贝构造函数
	ms1.show();
	ms2.show();
	ms3.show();
	ms4.show();
	ms5.show();
	ms6.show();
	ms4=ms1+ms2+ms6;//注意+中的temp和临时变量由拷贝构造函数生成
	ms4.show();
	ms1+=ms2+=ms3;//+=返回引用,不用拷贝构造函数
	ms1.show();
	if(ms1<ms4) {ms1.show();cout<<"应排在"<<endl;ms4.show();cout<<"之前"<<endl;}
	else {ms1.show();cout<<"应排在"<<endl;ms4.show();cout<<"之后"<<endl;}
	ms6=ms1;//ms6赋值不是返回引用,必须调用拷贝构造函数建立临时对象
	if(ms1==ms6) cout<<"串ms1与串ms6相同"<<endl; 
	ms1="C++ programming language";
	i=0;
	while(ms1[i]!='\0') cout<<ms1[i++];//读出
	cout<<endl;
	ms1[i++]='.';//写入
	ms1[i]='\0';
	i=0;
	ms1.show();
	cout<<endl;
	cout<<"ms1串长:"<<ms1.strlen()<<endl;
	cout<<"字符l在ms1中的下标为:"<<ms1.strchr('l')<<endl;
	ms2="ing";
	cout<<"ms2在ms1中的起始下标为:"<<ms1.strstr(ms2)<<endl;
	ms1.reverse();
	ms1.show();
	return 0;
}

*完成:
1)仔细阅读、理解、分析该程序,并调试运行;
2)考虑将属性char str[n] 改为char str,如何修改相应的成员函数(尤其是构造及析构函数)。
2)对示例程序中的运算符成员函数试着用友元函数替代实现。
3)对插入运算(即输出)符"<<",析取运算符(即输入)">>"运算,仿照课件用友元函数来实现,并测试之。

 Experimental procedure

#include<iostream>
using namespace std;
const int n = 256;
class mystring {
	/*
	char str[n];        //存放字符串的数组容器,可考虑定义指针,在构造函数中动态分配空间
	*/
	char* str;
	int maxsize;        //最大可用元素数,可防止数组出界,提高健壮性
	int last;           //已用元素最大下标
public:
	mystring() {
		last = -1;
		maxsize = n;
		str = new char[maxsize];//用new分配
		str[0] = '\0';
		cout << "缺省构造函数" << endl;
	}
	mystring(const char* s) {//当C字符串过长,初始化时采用截尾处理
		last = -1;
		maxsize = n;
		str = new char[n];//new分配空间
		do {
			last++;
			str[last] = s[last];
		} while (s[last] != '\0' && last < maxsize - 1);
		str[last] = '\0'; //截尾处理时,必须加串结束符
		cout << "构造函数" << endl;
	}
	mystring(const mystring& ms) { //devC++下不加const有问题?
		last = -1;
		maxsize = n;
		str = new char[n];//new分配空间
		do {
			last++;
			str[last] = ms.str[last];
		} while (last < ms.last);
		cout << "拷贝构造函数" << endl;
	}
	~mystring() {
		delete[]str;
		cout << "析构函数" << endl;
	}
	void show() {//如需重载<<,则参考补充课件,替代方法是用show()函数
		cout << str << endl;
	}
	int strlen() { return last; }; //求字符串长度
	void reverse();             //逆置字符串
	int strchr(char c);         //查找字符串中字符c首次出现的位置 
	int strstr(mystring str1); //查找主串中子串str1首次出现的位置
	char& operator[](int i) {   //返回引用,可读可写
		if (i > last) last = i;  //下标运算符,可添加长度但不查边界
		return str[i];
	}
	mystring& operator=(const mystring&);
	mystring& operator=(const char* ms);//这里重载的=是把C风格字符串赋给mystring
	/*
	mystring operator+(mystring&); //这里返回不能用引用
	mystring& operator+=(mystring&);
	bool operator<(mystring&);
	bool operator==(mystring&);
	*/
	//>>>>>>>>>>>>>>>>>用友元函数实现运算符重载
	friend mystring operator+(const mystring&, const mystring&);
	friend mystring& operator+=(mystring&, const mystring&);
	friend bool operator<(const mystring&, const mystring&);
	friend bool operator==(const mystring&, const mystring&);

	//>>>>>>>>>>>>>>>>>>>>>流输入输出运算符重载
	friend istream& operator>>(istream&, mystring&);
	friend ostream& operator<<(ostream&, const mystring&);
	//>>>>>>>>>>>>>>>>>>>>>>>>>>新增辅助函数
	int num_char();
};
void mystring::reverse() {
	int i = 0, j = last - 1;
	char temp;
	while (j > i) {//注意此处,从串两头同时向中间移动,重合或交错时停止
		temp = str[i]; //头尾交换
		str[i] = str[j];
		str[j] = temp;
		i++;
		j--;
	}
}
int mystring::strchr(char c) {
	int i;
	for (i = 0; i != last; i++) if (str[i] == c) return i;
	return -1; //未找到返回-1
}
int mystring::strstr(mystring str1) {
	int i = 0, k = 1;
	while (str[i] != '\0') {//只要主串还有字符未查,则继续
		while (str[i] != str1[0] && str[i] != '\0') i++;
		//找到主串含有子串的第一个字符,或主串查完停止
		if (str[i] != '\0') {//核对子串其他字符
			while (str[i + k] == str1.str[k] && k < str1.last) k++;//字符串结束符不比较
			if (k == str1.last) return i;//找到子串返回
			k = 1;
			i++;
		}
	}
	return -1; //未找到返回-1
}
mystring& mystring::operator=(const mystring& ms) {//这里返回值改为引用,不调用拷贝构造函数
	last = -1;
	do {
		last++;
		str[last] = ms.str[last];
	} while (last < ms.last);
	return *this;
}
mystring& mystring::operator=(const char* ms) { //这里返回值为引用,不调用拷贝构造函数
	last = -1;
	do {
		last++;
		str[last] = ms[last];
	} while (ms[last] != '\0' && last < maxsize - 1);
	str[last] = '\0'; //截尾处理时,必须加串结束符
	return *this;
}

//>>>>>>>>>>>>>>友元函数版本重载运算符函数如下>>>>>>>>>>>>>>>>>>>>>
mystring operator+(const mystring &m,const mystring& ms) {//注意+和+=的不同
	mystring temp(m);//+必须在一份拷贝上进行
	int i = -1;
	temp.last--;//串的结尾是结束符,连接时要覆盖掉
	do {
		temp.last++;
		i++;
		temp.str[temp.last] = ms.str[i];
	} while (i < ms.last && temp.last < ms.maxsize - 1);
	temp.str[temp.last] = '\0'; //截尾处理时,必须加串结束符
	return temp;//拷贝的临时变量生命期在调用它的表达式中
}
mystring& operator+=(mystring&m,const mystring&ms) {//+=在对象自身进行
	int i = -1;
	m.last--;//串的结尾是结束符,连接时要覆盖掉
	do {
		m.last++;
		i++;
		m.str[m.last] = ms.str[i];
	} while (i < ms.last && m.last < m.maxsize - 1);
	m.str[m.last] = '\0'; //截尾处理时,必须加串结束符
	return m;
}//这里返回值改为引用,不调用拷贝构造函数
bool operator<(const mystring&m,const mystring& ms) {   //重载<运算符
	int i = 0, k;
	do {
		k = m.str[i] - ms.str[i];
		i++;
	} while (k == 0 && i < m.last && i < ms.last);
	if (k < 0) return true;
	if (i == m.last && i != ms.last) return true;
	return false;
}
bool operator==(const mystring&m,const mystring& ms) {
	int i = 0, k;
	if (m.last != ms.last) return false;
	do {
		k = m.str[i] - ms.str[i];
		i++;
	} while (k == 0 && i < m.last);
	if (k != 0) return false;
	else return true;
}
//>>>>>>>>>>>>>>>流输入输出重载运算符友元函数定义如下
istream& operator>>(istream& is, mystring& x) {
	//为读取含空格的一行字符串
	//采用getline()
	is.getline(x.str, x.maxsize);
	x.last = x.num_char();
	return is;
}
ostream& operator<<(ostream& os, const mystring& m) {
	os << m.str << endl;;
	return os;
}
//>>>>>>>>>>>>>>>>>>>>>新增辅助函数
int mystring::num_char()
{
	for (int i = 0; i < maxsize; i++)
		if (!str[i])
			return i;
	return n;
}
int main() {
	int i;
	char* sp1 = (char *)"中国民航大学", * sp2 = (char*)"交通学院", * sp3 = (char*)"学生", * sp4 = (char*)"教师";
	mystring ms1(sp1), ms2(sp2), ms3(sp3);//ms1,ms2,ms3是用构造函数生成
	mystring ms4(ms3), ms5 = ms3, ms6; //ms4,ms5用拷贝构造函数生成;ms6用缺省构造函数
	ms6 = sp4; //ms6赋值是返回引用,不用拷贝构造函数
	ms1.show();
	ms2.show();
	ms3.show();
	ms4.show();
	ms5.show();
	ms6.show();
	ms4 = ms1 + ms2 + ms6;//注意+中的temp和临时变量由拷贝构造函数生成
	ms4.show();
	ms1 += ms2 += ms3;//+=返回引用,不用拷贝构造函数
	ms1.show();
	if (ms1 < ms4) { ms1.show(); cout << "应排在" << endl; ms4.show(); cout << "之前" << endl; }
	else { ms1.show(); cout << "应排在" << endl; ms4.show(); cout << "之后" << endl; }
	ms6 = ms1;//ms6赋值不是返回引用,必须调用拷贝构造函数建立临时对象
	if (ms1 == ms6) cout << "串ms1与串ms6相同" << endl;
	ms1 = "C++ programming language";
	i = 0;
	while (ms1[i] != '\0') cout << ms1[i++];//读出
	cout << endl;
	ms1[i++] = '.';//写入
	ms1[i] = '\0';
	i = 0;
	ms1.show();
	cout << endl;
	cout << "ms1串长:" << ms1.strlen() << endl;
	cout << "字符l在ms1中的下标为:" << ms1.strchr('l') << endl;
	ms2 = "ing";
	cout << "ms2在ms1中的起始下标为:" << ms1.strstr(ms2) << endl;
	ms1.reverse();
	ms1.show();
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 测试<<和>>
	mystring a, b;
	cin >> a >> b;
	cout << "逆序后" << endl;
	a.reverse(); b.reverse();
	cout << a << b ;
	return 0;
}

 Experimental results and analysis

在这里插入图片描述

 Experimental process analysis

在这里插入图片描述
The value of const char * type cannot be used to initialize the entity of char * type during vs compilation, so my solution is to use casts:

*vs编译过程中const char*类型的值不能用于初始化char 类型的实体,所以我才用的解决方法是利用强制类型转换:
在这里插入图片描述
As in the previous experiment, the overloaded assignment operator function must be a member function.
与上一个实验题一样,重载赋值运算符函数必须是成员函数。

在这里插入图片描述
When I first wrote code that overloaded > > operators, I didn’t think much about writing such a line of code.
最开始编写重载>>运算符的代码时,我没有过多思考的写出这样一行代码。
在这里插入图片描述
Later, when I kept debugging, I found that when the input string had spaces, the running result was not within my expectation.
Later, when I kept debugging, I found that when the input string had spaces, the running result was not within my expectation. Classes in istream, such as CIN, provide row oriented class member functions: getline() and get().
后来当我不断调试的时候发现,当输入的字符串中带有空格的时候,运行结果并不在我的预料范围内。istream中的类(如cin)提供了一些面向行的类成员函数:getline()和get()。
Then I changed the code to the following
在这里插入图片描述

owever, there is a serious disadvantage. After calling the reverse function, the original STR in mystring has not changed.
但还存在一个很严重的缺点,在调用reverse函数之后,原来mystring中的str没有任何改变。
Finally, I added a helper function to find the number of characters in the string. The code is as follows:
最后我添加了一个辅助函数来求字符串中的字符数目。代码如下:
在这里插入图片描述

Then the code in the overloaded > > function is finally debugged. Thank God, it’s finally successful.
然后对重载>>函数中的代码进行了最后的调试。感谢苍天,终于成功了。
在这里插入图片描述

By Suki
2020/5/4
颇有收获和进步的一天。

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值