[c++]字符串类各种操作的实现以及碰到的bug
[c++]字符串类各种操作的实现以及遇到的bug
代码如下:![[c++]字符串类各种操作的实现以及碰到的bug [c++]字符串类各种操作的实现以及碰到的bug](/default/index/img?u=aHR0cDovL3d3dy5teWV4Y2VwdGlvbnMubmV0L2ltZy8yMDE1LzA2LzE2LzIxMzI1MDMzMS5wbmc=)
字符串类的结构如下:
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”。一般是后者居多。
因此,当你遇见这个错误的时候,记得去检查一下自己数组的赋值吧。