理解string

本文详细介绍了C++中string类的三种遍历方式,包括operator[]、迭代器以及范围for,同时探讨了string的动态增长特性、容量管理、操作函数如insert、erase、resize等,以及与C语言兼容的c_str方法。
摘要由CSDN通过智能技术生成

初步理解string:

第一种遍历方式
operator[]    模拟的是数组的形式,他会自己显示调用operator,我们不用自己显示写出来
第二种遍历方式
迭代器:iterator    【通用的遍历方式,推荐掌握这类方法】
string::iterator  it = s.begin();
while(it != s.end())
{
    cout << *it <<" ";
    ++it;
}
cout  <<  endl;

begin  ————————  end【末尾的下一个位置】左闭右开
[                        )

typeid (it).name可以查看类型

第三种遍历方式:范围for
for(auto e: s)
{
    cout  <<  e << " ";
}
cout  <<  endl;

底层原理就是迭代器   


string是动态增长的字符数组
迭代器才是通用,下标方括号只是string的特殊用法,迭代器可以看成是指针
iterator:
正向反向iterator
正向反向const_iterator

capacity:容器
size()(推荐使用)=length()长度
max_size()编译器的最大值
capacity()容量
clear()只是清除数据,但是空间没有清除
shrink_to_fit()缩容,无法缩小到0,最小缩小到16【里面放了一个buffer】

reserve   保留保存
reverse   反转翻转

reserve(数字)直接扩容到想要的数字大小就行,但是例如reverse(100)不一定会给你只开100个字节
reserve不会缩容,除非比capacity大才会扩容
知道要插入多少数据,减少扩容,提高工作效率


empty()判空

resize(     )        size=17        capacity=32
          10        n<size                            删除
          20        size<n<capacity                    插入
            40        n>capacity                        扩容+插入
如果不给插入的值,会默认给'\0'

Element access:元素访问
运算符重载operator []
          at()
例如:string s1("hello world")
    s1[5]    断言异常
    s1.at(5)    抛异常
但是两个越界访问的报错结果不一样,常用还是[]
front()取头元素
back()取尾元素

Modifiers:
push_back()尾插一个字符
append()尾插字符串或者尾插多个字符
operator +=【最常用的就是这个!!!!】
+=' ';
+="apple";

assign()对这块空间进行覆盖

insert()头部插入数据
erase()删除数据 
replace()替换数据
上面这三个能少用就少用,因为要挪动数据,效率不高

find()查找数据
swap()交换数据
pop_back()尾插

String operations:
c_str( )    用于兼容c语言的string
data和c_str     差不多

find( )    从前往后找
substr()拷贝len个字符
可以用substr(pos1)或者substr(pos1,s1.size()-1)
rfind()    从后往前找

operator + 
s1 = "xxx";
s2 = "yyy";
s1+s2     【也支持字符串+string】xxxyyy

getline( )         获取一行string数据

to_string()     把整型和浮点数转成字符串
stoi()        把字符串转成整型和浮点数

不实用:
find_frist_of    正着找是否符合的字符
find_last_of    倒着找是否符合的字符

注意:cin  不认识空格和换行,他就会认为是分割

 除了string还有wstring   【w是宽字符】
window编程会遇到这个wstring:贪吃蛇之类的游戏

string        1
wstring         2
u16string    2
u32string    4


理解string 的底层原理:

}
public:
    string( )
    :_str(new char[1])
    ,_size(0)
    ,_capacity(0);
    {
        _str[0] = '\0';
    }
    
    //string(const  char*  str)
    //:_str(new  char [strlen(str)+1])    //这里strlen调用了三次
    //,_size(strlen(str))
    //,_capacity(strlen(str))
    //{
    //    strcpy(_str , str);
    //}
    
    string(const  char*  str  =  "")
        :_str(strlen(str))    
    {
        _capacity=_size;
        _size = new char[_capacity + 1];
        strcpy(_str , str);
    }

    //s2(s1)拷贝构造
    //传统写法
    string(const  string&  s)
    {
        _str  =  new  char[s._capacity+1];
        strcpy(_str,s._str);
        _size  = s._size;
        _capacity =  s._capacity;    
    }
    //s2(s1)
    //现代写法:本质是一种复用
    string (const  string&  s)
    {
        string  tmp(s.str);
        swap(tmp);
    }    
    


    //s1 =  s3;
    //传统写法
    string&  operator= (const  string&  s)
    {
        char*  tmp  = new  char[s._capacity +1];
        strcpy(tmp ,s._str);

        delete[] _str;
        _str = tmp;
        _size =  s._size;
        _capacity = s._capacity;
    }
    
    //现代写法
    string&  operator= (string   tmp)
    {
        swap(tmp);
        return  *this;
    }
    ~string()
    {
        delete[]  _str;
        _str  =  nuullptr;
        _size  =  _capacity  =  0;
    }

    //遍历
    //for循环到s1.size()
    //s1[i]下标方括号
    size_t  size() const
    {
        return _size;    
    }
    
    size_t capacity()  const
    {
        return _capacity;
    }
    
    char&  operator[] (size_t  pos)
    {
        assert(pos < size );
        return _str[pos];    
    }

    const  char&  operator[] (size_t  pos)  const
    {
        assert(pos < size );
        return _str[pos];    
    }

    typedef  char*  iterator;
    typedef  const  char*  const_iterator;

    iterator  begin()
    {
        return _str;    
    }    

    iterator  end()
    {
        return _str  + _size;    
    }
    
    iterator  begin()  const
    {
        return _str;    
    }    

    iterator  end()  const
    {
        return _str  + _size;    
    }
    void  reserve (size_t  n)
    {
        if(n > _capacity)
        {
            cahr*  tmp  =  new char [n];
            strcpy(tmp ,_str);
            delete[]  _str;
            _str =tmp;

            _capacity  =  n+ 1;
        }
    }
    
    void  push_back(char  ch)
    {
        if(_size  ==  _capacity)
        {
            reserve( _capacity == 0 ? 4 :2 * _capacity);
        }

        _str[_size] = ch;
        ++_size;
        _str [_size] = '\0';
    }
    void  append(const  char*  str)
    {
        size_t  len  =  strlen (str);
        if(_size  + len  > _capacity)
        {
            reserve(_size  + len );
        }

        strcpy(_str +size ,str);
        _size += len;
    }

    string& operator +=(char  ch)
    {
        push_back(ch);
        return *this;
    }

    string& operator +=(const char*  str)
    {
        append(str);
        return *this;
    }

     void insert(size_t  pos ,char  ch)
    {
        assert(pos  <= _size);
    
        if(_size  ==  _capacity)
        {
            reserve( _capacity == 0 ? 4 :2 * _capacity);
        }
        
        size_t end  = _size;
        while(end >= (int)pos)//强转
        {
            _str[end+1] = _str[end];
            --end;
        }
        _str[pos] = ch;
        ++_size;
    }
     void insert(size_t  pos ,const  char* str)
    {
        assert(pos  <=  _size);
        size_t  len  = strlen (str);
        if(_size  + len > _capacity )
        {
            reserve(_size + len );
        }
        size_t  end  =_size +len;
        while(end  >  pos + len -1)
        {
            _str[end] = _str[end - len];
            end--;
        }
        strncpy(_str  + pos ,str ,len);
        _size  += len;
    }
    
    void  erase(size_t  pos,size_t  len  =  npos)
    {
        assert(pos < _size);
        if(len  == npos ||  pos  > = _size - len)        //【写成pos  +  len>= _size】有溢出风险
        {
            _str[pos] = '\0';
            _size  =  pos;
        }
        else
        {
            strcpy(_str  + pos , str + pos +len);
            _size  -=  len;
        }
    }    

    void  resize ( size_t  n, char  ch = '\0')
    {
        if(n  <  _size)
        {
            _str[n]= '\0';
            _size  = n;
        }
        else
        {
            reserve(n);    
            for(size_t   i = _size ;  i  <n  ; i++)
            {
                _str[i]  =  ch;
            }
            _str[n]  =  '\0';
            _size  =  n;
        }
    }

    void  swap( string&  s)
    {
        std::swap(_str,s._str);
        std::swap(_size,s._size);
        std::swap(_capacity,s._capacity);
    }
    
    size_t  find(char ch)  const
    {
        assert(pos < _size);
        for(size_t  i  =0; i <  _size;i++)
        {
            if(_str[i]  ==  ch)
                return  i ;
        }
        return npos;
    }
    
    size_t  find(char ch,size_t  pos  = 0)  const
    {
        assert(pos < _size);
        for(size_t  i  =pos ; i <  _size;i++)
        {
            if (_str[i]  ==  ch)
                return  i ;
        }
        return npos;
    }
    
    size_t  find(const  char*  sub,size_t  pos  = 0)  const
    {
        //kmp算法      实践不实用
        assert(pos < _size);
        const char*  p = strstr(str,sub);
        if(p)
        {
            return p  - str;
        }
        else
        {
            return npos;
        }
    }

    string  substr (size_t  pos  =  0;  size_t  len = npos)
    {
        string sub;
        if(len  ==  npos ||  len  >=  _size - pos)
        {
            for(size_t  i  = pos; i< _size;i++)
            {
                sub+=_str[i];
            }
        }
        else
        {
            for(size_t  i  = pos; i< pos + len ;i++)
            {
                sub+=_str[i];
            }

        }
    }
    
    bool  operator== (const  string&  s1,const  string&  s2)
    {
        int ret  =  strcmp(s1.c_str,s2.c_str);
        return ret  == 0;
    }
    
    bool  operator< (const  string&  s1,const  string&  s2)
    {
        int ret  =  strcmp(s1.c_str,s2.c_str);
        return ret  < 0;
    }
    
    bool  operator<= (const  string&  s1,const  string&  s2)
    {
        return  s1< s2 ||  s1== s2;
    }

    bool  operator> (const  string&  s1,const  string&  s2)
    {
        return  !(s1<=s2);
    }
    
    bool  operator>= (const  string&  s1,const  string&  s2)
    {
        return  !(s1<s2);
    }
    
    bool  operator!= (const  string&  s1,const  string&  s2)
    {
        return  !(s1==s2);
    }
    
    ostream&  operator<<(ostream& out ,const  string&  s)
    {
        for(auto  ch :s)
        {
            out << ch;
        }
        return out;
    }
    
    
    istream&  operator>>(istream& in ,const  string&  s)
    {
        s.clear();
        char ch;
        //in  >> ch;
        ch = in.get( );
        char  buff[128];
        size_t  i  =0;
        while(ch  != ' '&& ch != '\n')
        {
            buff[i++] = ch;
            if( i  ==  127)
            {
                buff[127]  =  '\0';
                s+=buff;
                i = 0;
            }
            ch = in.get( );
        }

        if(i > 0)
        {
            buff[i]  =  '\0';
            s+=buff;
        }
        return in; 
    }    
    
    void clear()
    {
        _size  =  0;
        _str[_szie]  = '\0';
    }

    istream&  getline(istream& in ,string&  s)
    {
        s.clear();
        char ch;
        //in  >> ch;
        ch = in.get( );
        while(ch  != '\n ')
        {
            s+= ch;
            ch = in.get( );
        }
        return in; 
    }
private:
    const char* _str  =  nullptr;
    size_t  _size  =  0 ;
    size_t  _capacity  =  0;
public:
    static  const  int  npos;
};

我赌你的枪里没有子弹!!!!
问题一:析构多次
【智能指针】引用计数:析构时检查引用计数,如果减完以后计数 == 0 代表当前是最后一个管理资源的对象,那就释放

问题二:一个修改会影响另一个
发生写时拷贝:检查引用计数,如果 == 1,说明资源是自己独占的,不用拷贝
如果大于1,先拷贝(深拷贝)再写,这就是写时拷贝

反正都要拷贝,这样做的意义是啥?
不是每个对象都要修改,我赌你不会修改
 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值