0


简单复写C++string类

主要写增删查改和几种常见的构造方式:

文章目录

定义先确定string类中成员变量:

private:char* _str;
        size_t _size;//实际空间
        size_t _capacity;//有效空间,真实容量没算\0;staticconst size_t npos;//位置};

1.1第一种构造方式 string(const char *s) :

//s1("HAOHAO")string(constchar* str):_size(strlen(str))//开空间初始化,_capacity(_size){
            _str=newchar[_capacity +1];strcpy(_str, str);}

1.2.第二种构造方式拷贝构造://3.string(const string & str,string size_type n = npos):

这里需要用深拷贝,浅拷贝会报错,浅拷贝并没有直接开辟空间而是指针指向了被拷贝的空间,看起来没什么问题,但是程序结束时会报错,因为结束时会调用析构函数,按照下图所示s2会先调用析构函数,之后s1也会调用析构函数,此时s1的空间已经被s2释放了所以程序报错;

string s1("HAOHAO");
string s2=(s1);

在这里插入图片描述

深拷贝又有好几种写法,分为古代和现代两种写法

//深拷贝古代写法:啥都亲力亲为string(const string& s):_size(s._size),_capacity(s._capacity){
            _str =newchar[_capacity +1];strcpy(_str, s._str);}//    深拷贝现代写法:找别人干活string(const string& s):_str(nullptr){
            string tmp(s._str);//这里s._str的类型是char*所以调用的是我们自己写的第一种构造方式//这个swap是我们自己写的函数,后面重载操作符 =的时候会说为啥要自己写this->swap(tmp);}

1.3.重载操作符 =:

这也分了古代和现代两种写法,现代中用了我们自定义的swap函数,如果用swap(_str,s.str)这么写只是把指针_str和s.str这两个指针互换了,this的容量并没有交换无法全部拷贝到

//s1=s3;古代写法
        string&operator=(const string& s){//释放掉原空间,避免浪费,可能s1很大s3很小if(this!=&s){//s3=s3这种情况char* tmp =newchar(s._size);//先开辟空间再释放strcpy(tmp, s._str);delete[] _str;
                _str = tmp;//传的地址
                _size = s._size;
                _capacity = s._capacity;}return*this;}//现代写法
        string &operator=(const string &s){if(this!=&s){
                string tmp(s);//普通的swap(_str,tmp_str)只是交换了_str指针的方向但是string类里size和capacity还跟以前一样,会出问题this->swap(tmp);
                cout <<"交换后"<< endl;

                cout <<this->_str << endl;
            \
            }return*this;}voidswap(string& s){
        
            std::swap(_str, s._str);
            std::swap(_size, s._size);
            std::swap(_capacity, s._capacity);}

1.4.重载运算符[ ]、s._str()、size()函数:

char&operator[](size_t pos){assert(pos < _size);//防止越界直接断死return _str[pos];}constchar*c_str(){return _str;}
        size_t size()const{return _size;}

1.5.查找单个字符和字符串:

//查找单个字符
        size_t find(constchar ch){for(size_t i =0; i < _size; i++){if(ch == _str[i]){return i;}}return npos;//没有找到返回npos}//查找字符串
        size_t find(constchar*s,size_t pos=0){for(size_t i =0; i < _size; i++){//:strstr(str1,str2) 函数用于判断字符串str2是否是str1的子串。如果是,则该函数返回str2在str1中首次出现的地址;否则,返回NULL。constchar* ptr =strstr(_str + pos, s);if(ptr ==nullptr){return npos;}else{return ptr - _str;}}return npos;//没有找到返回npos}

1.6.reserve()和resize()函数:

扩容reserve和resize: reserve的逻辑是先把内容拷贝下来,存在tmp中再把原来的空间给删掉;resize的容量可能会被变小,变小的话直接在n的位置加上’\0’,然后改变_size,如果变大又分了两种情况(1)n比_size大比_capacity小,(2)n直接比capacity大。
第一种情况直接在比 下标size 大的填上‘\0’占位;
第二种情况先扩容再占位;
在这里插入图片描述

voidreserve(size_t n){//改变capacity n比原来的那么就变成n 比原来小就不变if(n > _capacity){char* tmp =newchar[n +1];//\0strcpy(tmp, _str);delete[] _str;
                _str = tmp;
                _capacity = n;}}voidresize(size_t n,char ch='\0'){if(n <= _size){//resize跟reserve不一样它如果resize一个比它之前size小的数会缩容量的,最后一个位置填‘\0’
                _str[n]='\0';
                _size = n;}else{if(n > _capacity){reserve(n);}memset(_str + _size, ch, n - _size);//扩容后把空间填充从size开始
                _str[n]='\0';
                _size = n;}}

1.7.push_back()函数:

voidpush_back(char ch){//判断是否为空和是否已经满了,如果本身没有空间扩容四个字节,如果本身有空间但是满了直接扩容两倍if(_size == _capacity){reserve(_capacity==0?4: _capacity *2);}

            _str[_size]= ch;++_size;
            _str[_size]='\0';}

1.8.inset()函数:

指定位置插入字符或字符串:先判断容量是否够不够就扩,然后把从最后一个字符往后移,直到pos位置为空,end一定要在最后一个字符的后面一个位置也就是‘\0’的位置,如果end=_size,判断条件while (end>=(pos) ,如果此时在第0个位置插入end最后会变成-1程序歇火;

插入字符串也是一样的也是从最后面开始移动但是end要在size+len(插入字符串长度)的位置,直到找到pos

在这里插入图片描述

//插入字符
        string&insert(size_t pos,char ch){assert(pos <= _size);//判断容量是否满了if(_size == _capacity){reserve(_capacity ==0?4: _capacity *2);}//这么写 在第0个位置插入时会报错,end变为-1直接歇火size_t类型不能为负数,转为int的时候while (end>=pos)这个判断还会出问题要// while (end>=(int)pos)//size_t  end = _size;往后移直到第pos个位置为空//while (end>=pos) {//    _str[end + 1] = _str[end];//    --end;//}//直接 HAO\0,把end放在斜杠0后面
            size_t end = _size+1;while(end > pos){
            
                _str[end]= _str[end -1];

                end--;}
            _str[pos]= ch;++ _size;return*this;}//插入字符串
        string&insert(size_t pos,constchar*ch){assert(pos <= _size);//先看容量够不够
            size_t len =strlen(ch);if(_size + len > _capacity){reserve(_size+len);}
            size_t end = _size + len;while(end >=pos+len){

                _str[end]= _str[end - len];

                end--;}strncpy(_str, ch, len);
            _size+=len;return*this;}

1.9 append()函数:

在末尾插入字符串扩容时要结合实际情况扩容,还有一种简便写法直接调用上面写的insert函数

voidappend(constchar* ch){//扩容不能单纯的扩两倍可能不够万一要结合实际
            size_t len =strlen(ch);if(_size + len > _capacity){this->reserve(_size+len);}strcpy(_str + _size, ch);//从上一个单词的末尾插}voidappend(constchar* ch){insert(_size, ch);}
标签: c++ 开发语言

本文转载自: https://blog.csdn.net/qq_44844588/article/details/129282035
版权归原作者 所有, 如有侵权,请联系我们删除。

“简单复写C++string类”的评论:

还没有评论