字符串类的结构如下:
Class String:
public:
构造函数:1:未给定初始化的内容则默认指向只包含'\0'的字符串(即空串)---->开辟一个字节的空间,并用'\0'初始化 2:给定初始化的内容则开辟相应的空间并初始化为相应内容;
析构函数:释放动态开辟的空间,即m_data指向的内存空间
初始化函数
赋值函数
private:
char * m_data;------->>>指向动态开辟的空间
对字符串类实现如下操作:
String operator+(const String &s); //s = s1 + s2
String operator+=(const String &s); //s1 += s2
char& operator[](int index);
bool operator==(String &s);
bool operator!=(String &s);
bool operator>(String &s); //s1 > s2
bool operator<=(String &s);
bool operator<(String &s);
bool operator>=(String &s);
ostream& operator<<(ostream &out, const String &s);
istream& operator>>(istream &in, String &s);
代码如下:
#include<iostream>
using namespace std;
//友元函数声明
class String;
ostream& operator<<(ostream &out,const String &str);
istream& operator>>(istream &in,String &str);
class String
{
//默认的构造函数
public:
String(const char *str = NULL)
{
if(NULL == str)
{
m_data = new char[1];
m_data[0] = '\0';
}
else
{
m_data = new char[strlen(str) + 1];
strcpy(m_data,str);
}
}
~String()
{
delete []m_data;
}
String(const String &str)
{
m_data = new char[strlen(str.m_data) + 1];
strcpy(m_data,str.m_data);
}
String& operator=(const String &str)
{
if(this != &str)
{
delete []m_data;//此步骤易忘记,从而可能造成内存泄露(原因,未考虑对像可能已经过存在,开辟过内存)如:String s("123");s = s1;
m_data = new char[strlen(str.m_data) + 1];
strcpy(m_data,str.m_data);
}
return *this;
}
//运算符重载
//连接:对像 = 对像 + 对像
String operator+(const String &str)
{
char *s = new char[strlen(m_data) + strlen(str.m_data) + 1];
strcpy(s,m_data);
strcat(s,str.m_data);
String tmp(s); //构造临时变量 //return String(s);!!!!!!错误!!
delete []s; //释放开辟的内存,防止内存泄露
return tmp;
}
//连接:对像 += 对像 s1 += s
String& operator+=(const String &str)
{
char *s = new char[strlen(m_data) + strlen(str.m_data) + 1];
strcpy(s,m_data);
strcat(s,str.m_data);
delete []m_data;//释放原来的空间
m_data = s; //指向新开辟的空间
return *this;
}
//字符串是否相等,相等返回真,否则返回假 s1 == s?
bool operator==(const String &str)
{
if(strcmp(m_data,str.m_data) == 0)
return true;
else
return false;
}
//字符串是否不相等,不相等返回真,否则返回假 s 1!= s?
bool operator!=(const String &str)
{
if(strcmp(m_data,str.m_data) == 0)
return false;
else
return true;
}
//s1 > s
bool operator>(const String &str)
{
if(strcmp(m_data,str.m_data) > 0)
return true;
else
return false;
}
//s1 >= s
bool operator>=(const String &str)
{
if(strcmp(m_data,str.m_data) >= 0)
return true;
else
return false;
}
//s1 < s
bool operator<(const String &str)
{
if(strcmp(m_data,str.m_data) < 0)
return true;
else
return false;
}
//s1 <= s
bool operator<=(const String &str)
{
if(strcmp(m_data,str.m_data) <= 0)
return true;
else
return false;
}
char& operator[](int index)
{
return m_data[index];
}
friend ostream& operator<<(ostream &out,const String &str);
friend istream& operator>>(istream &in,String &str);
private:
char *m_data;
};
ostream& operator<<(ostream &out,const String &str)
{
out<<str.m_data<<endl;
return out;
}
istream& operator>>(istream &in,String &str)
{
// std::cout<<"你可以输入"<<strlen(str)<<"个字符"<<endl;
in>>str.m_data;
return in;
}
int main()
{
String s("_helen"); <span style="white-space:pre"> </span> //测试构造
String s1("zyh");
s1 += s; <span style="white-space:pre"> </span>//测试加等:+=
cout<<s1; //测试输出:<<
String s2 = s1; //测试赋值:=
cout<<s2;
String s5 ="1123"; //测试下标:[]
s5[1] = 'd';
cout<<s5;
String s6 ("zyh");
String s7 ("zyh_helen");
if(s6 > s7) <span style="white-space:pre"> </span>//测试比较
{
cout<<"s6 > s7"<<endl;
}
else
{
cout<<"s6 < s7"<<endl;
}
String s4("zyh_helen");
cin>>s4; //测试输入
cout<<s4;
return 0;
}
注意:
String& operator=(const String &str)
{
if(this != &str)
{
delete []m_data;//此步骤易忘记,从而可能造成内存泄露(原因,未考虑对像可能已经过存在,开辟过内存)如:String s("123");s = s1;
m_data = new char[strlen(str.m_data) + 1];
strcpy(m_data,str.m_data);
}
return *this;
}
//运算符重载
//连接:对像 = 对像 + 对像
String operator+(const String &str)
{
char *s = new char[strlen(m_data) + strlen(str.m_data) + 1];
strcpy(s,m_data);
strcat(s,str.m_data);
String tmp(s); //构造临时变量 //return String(s);!!!!!!错误!!
delete []s; //释放开辟的内存,防止内存泄露
return tmp;
}
//连接:对像 += 对像 s1 += s
String& operator+=(const String &str)
{
char *s = new char[strlen(m_data) + strlen(str.m_data) + 1];
strcpy(s,m_data);
strcat(s,str.m_data);
delete []m_data;//释放原来的空间
m_data = s; //指向新开辟的空间
return *this;
}
就像:(由于种种原因)另寻新欢,只有处理好前妻的关系(离婚手续,安置费),才可以与新欢开始新的生活,若未处理好与前妻的关系,直接抛弃,那么总有一天你会付出代价,而且是惨重的代价!
测试过程中遇到的如下bug:
测试如下:
解释如下:
String s("123");--->调用构造函数开辟四个字节:存放123\0
cin时存入1234\0,超出了开辟空间的范围,释放空间时出现错误!!
String s;--->调用构造函数开辟一个字节:存放\0
cin时存入11\0,超出了开辟空间的范围,释放空间时出现错误!!
即动态开辟n个字节的空间,初始化时超过其范围,就会出现如上所述bug:DAMAGE:
after Normal block
以下来自:点击打开链接
前几天师弟调试程序的时候出现了这样一个错误,出错的位置是在delete [] 一个动态分配的数组时出现的。
经过调查发现错误是因为他之前在给数组赋值的时候越界了1个位置。
也就是double * a= new double [5],结果赋值的时候给a[5]=5。使用c++的同学都知道,一个5维的动态数组,调用时应该是0~4,但是这里给a[5]赋值并没有出错,反而是delete时才会出错。
这其实是因为在动态分配内存的时候往往分配的是一个连续的地址,这一点从可以使用*[a+3]来取值就能够知道。
因此,在动态分配的时候,会在数组界限外加一个用来标识数组范围的标志,例如a数组,就会在a[-1]和a[5]有两个标志,如果我们在这两个位置赋值,赋值和调用时并不会出错,而是在delete [] a时出错,错误的名称就是“DAMAGE: before Normal block”和“DAMAGE: after Normal block”。一般是后者居多。
因此,当你遇见这个错误的时候,记得去检查一下自己数组的赋值吧。