String系列——基础实现
来源:互联网 发布:学php的就业面 编辑:程序博客网 时间:2024/06/07 07:42
本节实现一个简单的string类,以方便后面的string系列能够顺利进行,设计string系列旨在学习和理解一些底层技术,比如COW、内存池等等,另一方面学习语言的基本功,同时也可以加深对string类的理解。
代码可能很长,但是学习的最好办法就是阅读代码。
类定义
这里定义了string类的一些基本函数
class MString{public: //构造函数 MString():m_len(0),m_str(0){} MString(const MString& s); MString(const char* s); MString(size_t n); ~MString(); //赋值操作符,实现对象赋值 MString& operator=(const MString& s); //赋值操作符,实现字符串赋值 MString& operator=(const char* s); //转换成c类型字符串 const char* c_str(){ return m_str; } //判断字符是否为空 bool empty(){ return m_len>0? true:false; } //返回字符串长度 size_t length(){ return m_len; } //返回字符串大小 size_t size(){return m_len;} //删除pos开始的n个字符,不能为左值 const MString& erase(size_t pos, size_t n); //对象末尾添加字符串s MString& append(const MString& s); //返回从pos开始的n个字符 MString substring(size_t pos,size_t n); //从位置pos开始插入字符串s MString& insert(size_t pos,const MString& s); MString& insert(size_t pos,const char* s); //把字符串s中从pos开始的n个字符返回赋给当前字符串 MString& assign(const MString& s, size_t,size_t); MString& assign(const char* s, size_t,size_t);private: size_t m_len; char* m_str;};
实现
#include "mstring.h"MString::MString(const MString& s){ m_len = s.m_len; m_str = new char[m_len+1]; strcpy(m_str,s.m_str);}MString::MString(const char* s){ if (s == NULL) { return; } m_len = strlen(s); m_str = new char[m_len+1]; strcpy(m_str,s);}MString::MString(size_t n){ m_len = n; m_str = new char[n+1];}MString::~MString(){ delete[] m_str; m_len = -1;}//赋值操作符,深拷贝MString& MString::operator=(const MString& s){ if (strcmp(this->m_str, s.m_str) == 0) //两个字符串相等,则直接返回。 { return *this; } if (s.m_len > 0) //如果两个字符串不想等,且s中存在元素。 { if (m_len > 0) { delete[] m_str; } this->m_len = s.m_len; m_str = new char[m_len + 1]; strcpy(m_str, s.m_str); m_str[m_len] = '\0';//strcpy已近复制了'\0' } //若s为空,直接返回本身,若不为空返回深拷贝后的自己 return *this;}//字符串赋值MString& MString::operator=(const char* s){ if (s == NULL) { return *this; } if (this->m_len > 0) { delete[] m_str; } this->m_len = strlen(s); this->m_str = new char[m_len+1]; strcpy(m_str,s); m_str[m_len] = '\0'; //strcpy已近复制了'\0' return *this;}//删除pos开始的n个字符,pos位置以0开开始const MString& MString::erase(size_t pos, size_t n){ assert(pos < m_len && pos > 0 && n > 0 && n < m_len); if (pos + n < m_len) //如果删除的长度在len范围内 { int i; int move_num = m_len - pos - n ; for (i = 0;i < move_num;i++) { m_str[pos+i] = m_str[pos + n + i]; } m_str[pos + i] = '\0'; } else //删除的长度超过m_len { m_str[pos] = '\0'; } return *this;}//对象末尾添加字符串sMString& MString::append(const MString& s){ if (s.m_len < 1) { return *this; } m_len += s.m_len; char* tmp_str = new char[m_len +1]; strcpy(tmp_str,m_str); strcat(tmp_str,s.m_str); tmp_str[m_len] = '\0'; delete[] m_str; m_str = tmp_str; return *this;}//返回从pos开始的n个字符MString MString::substring(size_t pos,size_t n){ assert(pos < m_len && pos > 0 && n > 0 && n < m_len); MString* new_string = new MString(n); if (pos + n < m_len) //截取长度在字符串范围内 { while(n--) { new_string->m_str[n] = this->m_str[pos + n]; } new_string->m_str[new_string->m_len] = '\0'; } else //截取长度在字符串之外 { strcpy(new_string->m_str, &this->m_str[pos]); new_string->m_str[this->m_len - pos]='\0'; } return *new_string;}//从位置pos开始插入字符串sMString& MString::insert(size_t pos,const MString& s){ assert(pos >= 0 && pos <= m_len); m_len += s.m_len; char* tmp_str = new char[m_len +1]; //赋值新的字符串中 strncpy(tmp_str,m_str,pos); tmp_str[pos] = '\0'; strcat(tmp_str,s.m_str); strcat(tmp_str,&m_str[pos]); tmp_str[m_len] = '\0'; //释放原字符串 delete[] m_str; m_str = tmp_str; return *this;}//从位置pos开始插入字符串sMString& MString::insert(size_t pos,const char* s){ assert(pos >= 0 && pos <= m_len); m_len += strlen(s); char* tmp_str = new char[m_len +1]; //赋值新的字符串中 strncpy(tmp_str,m_str,pos); tmp_str[pos] = '\0'; //注意这里要加结束符,否则strcat会一直找到'\0'时才开始连接。 strcat(tmp_str,s); strcat(tmp_str,&m_str[pos]); tmp_str[m_len] = '\0'; //释放原字符串 if (m_str != NULL) { delete[] m_str; } m_str = tmp_str; return *this;}//把字符串s中从pos开始的n个字符返回赋给当前字符串MString& MString::assign(const MString& s, size_t pos,size_t n){ assert(s.m_len >= pos + n && pos >= 0 && n>0); if (m_len == 0 && m_str == 0) { m_len = n; m_str = new char[m_len +1]; strncpy(m_str, &s.m_str[pos],n); m_str[m_len] = '\0'; } else { m_len = n; char* tmp_str = new char[m_len +1]; strncpy(tmp_str, &s.m_str[pos],n); tmp_str[m_len] = '\0'; delete[] m_str; m_str = tmp_str; } return *this;}MString& MString::assign(const char* s, size_t pos,size_t n){ size_t slen = strlen(s); assert(slen >= pos + n && pos >= 0 && n>0); if (m_len == 0 && m_str == 0) { m_len = n; m_str = new char[m_len +1]; strncpy(m_str, &s[pos],n); m_str[m_len] = '\0'; } else { m_len = n; char* tmp_str = new char[m_len +1]; strncpy(tmp_str, &s[pos],n); tmp_str[m_len] = '\0'; delete[] m_str; m_str = tmp_str; } return *this;}
其中,某些方法是参考vector实现思想写的。下一节,操作符重载总结(http://blog.csdn.net/z702143700/article/details/47166437)
2015-09-17修改:看了剑指offer后发现,自己 写代码还是很低级的。拿operator=来说。
实现中,先delete 掉m_str,再申请一段内存的时候,如果内存不足,new抛出异常,此时m_str就变成了一个空指针。这样很容易导致程序崩溃。
要实现这种异常安全性,必须先new到内存后再去释放。剑指offer中给了一个很好的解法:先创建一个临时实例,再交换临时和原来实例。
MString& MString::operator=(const MString& s){ if (&s != this) { MString* tms = new MString(s); char* ptmp = tms->m_str; tms->m_str = this->m_str; this->m_str = ptmp; } return *this;}
0 0
- String系列——基础实现
- string系列——StringBuilder实现
- String类基础实现
- 数据结构基础系列——单链表的实现
- 数据结构基础系列——链栈的实现
- mongodb基础系列——java操作mongodb实现CURD
- mongodb基础系列——java操作mongodb实现CURD
- Java基础——String
- Java 基础——String
- Spark 基础 —— String
- Java基础—String类
- C++基础学习—string
- Java基础—String类
- Java基础系列六、IDE+Object+String
- String系列——String关键源码解析
- String系列——JVM对String的处理
- String系列——JVM对String的处理
- [Java--基础]----String hashCode实现
- Mysql分表准则
- HDU 3622 Bomb Game(2-SAT+二分)
- SpingMVC中的HandlerMapping
- Mac OS上反编译android app的环境搭建
- AndroidManifest.xml文件详解(uses-feature)
- String系列——基础实现
- 能量英语在七月
- 数据List刷新UI的Items显示(比如服务器给客户端刷新好友列表) 方法(2)
- HTML5新特性归纳和同类比较
- C++中的 extern "C"
- 使用git rebase合并多次commit
- width:auto和width:100%的区别
- Android--service里 onstart()onStartCommand()方法的区别
- ZOJ 3574 Under Attack II 归并排序求逆序对