String类使用及模拟

01. string类

  • string是表示字符串的字符串类
  • 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
  • string在底层实际是:basic_string模板类的别名,typedef basic_string<char, char traits, allocator> string
  • 不能操作多字节或者变长字符的序列。
  • 在使用string类时,必须包含#include头文件以及using namespace std
    在这里插入图片描述

string类是basic string模版类的一个实例,basic string实例化出了四种类型。

在这里插入图片描述


02. string默认成员函数

2.1 构造函数

构造函数说明
string()默认构造,创建空字符串(长度为0
string(const char* s)用C风格字符串初始化
string(const char* s, size_t n)用字符数组前n个字符初始化(示例取"hello_")
string(const string& str)拷贝构造,用另一个string对象初始化
string(const string& str, size_t pos, size_t len)pos开始截取len个字符(示例从s2位置24个字符,得"llo_"
string(size_t n, char ch)创建包含nch的字符串(示例生成"AAAAAA"

注意:

  • nposstring 类的静态常量,表示最大可能值
  • 示例中 s5len 若超出范围自动截断到字符串末尾
  • 所有构造方式均会分配内存并管理自己的字符存储(深拷贝)
void test(){
    //我们不传参数,系统为我们创建一个长度为0的字符串
    string s1;                    // string();
    //使用传递的字符串创建`string`类,并进行初始化
    string s2("hello_world");     // string(const char* s);
    //用字符数组的前`n`个字符来初始化string类对象。
    string s3("hello_world", 6);  // string(const char* s, size_t n),
    //通过同类型的对象来初始化(拷贝构造)
    string s4(s2);                // string(const string& str);
    //用`str`中的第`pos`个位置后面`len`个字符进行初始化对象。
    string s5(s2, 2, 4);          // string(const string& str, size t pos, size t len=npos);
    //创建`string`类对象,并将其内容设置成n个ch。
    string s6(6, 'A');            // string(size tn, char ch);
}
int main(){
    test();
    return 0;
}

在这里插入图片描述

2.2 析构函数

在这里插入图片描述

2.3 复制运算符重载

void test1(){
    string s1;
    string s2="hello_world";//拷贝构造
    s1 = s2;//string& operator= (const string& str);

    string s3;
    s3 = "helle_";//string& operator= (const char* s);

    string s4;
    s4 = 'q';//string& operator= (char c);
}
int main(){
    test1();
    return 0;
}

在这里插入图片描述


03. string使用

string类对象的访问及遍历


04. string模拟实现

4.1 深浅拷贝

默认拷贝构造/赋值的行为,即不手动实现时,默认进行浅拷贝,多个对象共享同一块内存,这个时候当程序执行完调用析构函数释放空间时,对指向的同一块区域多次释放,导致程序崩溃。

在这里插入图片描述

上述string类没有显式定义其拷贝构造函数与赋值运算符重载,此时编译器会合成默认的,当用s1构造s2时,编译器会调用默认的拷贝构造。最终导致的问题是,s1s2共用同一块内存空间,在释放时同一块空间被释放多次而引起程序崩溃,这种拷贝方式,称为浅拷贝。


4.2 构造函数模拟实现

在这里插入图片描述

 string(const char *str = "") // 全缺省构造函数
        : _str(new char[strlen(str) + 1]), _size(0), _capacity(0)
    { // 深拷贝
        strcpy(_str, str);
    }
    string(const string &s) // 拷贝构造 string s1(s2);this指向s1被新创的对象
        : _str(new char[strlen(s._str) + 1])
    {
        strcpy(_str, s._str);
        _size = s._size;
        _capacity = s._capacity;
    }
    string(const char *s)
    {
        size_t len = strlen(s);
        _str = new char[len + 1];
        memcpy(_str, s, len + 1);
        _size = len;
        _capacity = len;
    }
    string(const char *s, size_t n)
    {
        int len = strlen(s);
        if (n > len)
        {
            n = len;
        }
        _str = new char[n + 1];
        memcpy(_str, s, n);
        *(_str + n) = '\0'; // 重,第n个位置补\0
        _size = n;
        _capacity = n;
    }
    string(size_t n, char c)
    {
        _str = new char[n + 1];
        for (size_t i = 0; i < n; i++)
        {
            _str[i] = c;
        }
        _str[n] = '\0';
        _size = n;
        _capacity = n;
    }

4.3 operator[]模拟实现

在这里插入图片描述

    string &operator=(const string &str) // s1=s2,s1是新的
    {
        if (this != &str)
        {   
            char *tmp = new char[strlen(str._str) + 1];
            memcpy(tmp, str._str, strlen(str._str) + 1);
            delete[] _str;
            _str = tmp;
            _size = str._size;
            _capacity = str._capacity;
            return *this;
        }
    }
    string &operator=(const char *s) // s1="ssssss"
    {
        delete[] _str;
        _str = new char[strlen(s) + 1];
        memcpy(_str, s, strlen(s) + 1);
        _size = _capacity = strlen(s);
        return *this;
    }
    string &operator=(char c) // s1='c'
    {
        delete[] _str;
        _str = new char[2];
        _str[0] = c;
        _str[1] = '\0';
        return *this;
    }

4.4 迭代器与下标访问

4.4.1 迭代器

在string中将迭代器简单理解成一个指针,但实际不是这样,更复杂。

typedef char* iterator;
typedef const char* const iterator;
iterator begin(){
return _str;
}
iterator end(){
return(_str+_size);
}
iterator begin()const{...}

在这里插入图片描述

  • begin()end(): 正向迭代器
  • rbegin()rend(): 反向迭代器
...
string str = "Hello, World!";
    // 正向迭代器遍历
    string::iterator it = str.begin();
    while (it != str.end()) {
        std::cout << *it;
        ++it;
    }

4.4.2 operator[]访问
char& operator[](sie_t pos){
    return *(_str+pos);//==str[pos]
}
char& operator[](sie_t pos)const{...}

4.5 增删查改

4.5.1 reserve()扩容

当我们进行增加元素时,需要判断当前元素是否够用。然后开辟新空间,把原来数据转移到新空间,释放旧空间。

    void reserve(size_t n){
        if(n>_capacity){
            //开辟新空间
            char* tmp = new char[n + 1];
            memcpy(tmp, _str, _size);
            delete[] _str;//释放旧空间
            _str = tmp;//指向新空间
            _capacity = n;//改变现在容量
        }
    }

4.5.2 append()追加

在这里插入图片描述

 string &append(const string &str)
    { // 追加
        // 开辟新空间
        size_t len = str._size;
        if (len + _size > _capacity)
        {
            reserve(len + _size);
        }
        for (size_t i = 0; i < len; i++)
        {
            _str[_size + i] = str._str[i];
        }
        _size = len + _size;
        _str[_size] = '\0';
    }
    string &append(const char *str)
    { // 字符串存在代码段
        // int len = strlen(s);
        // if (len+_size>_capacity)
        // {
        //     reserve(len + _size);
        // }
        // for (size_t i = 0; i < len;i++){
        //     _str[_size + i] = s[i];
        // }
        // _size = len + _size;
        // _str[_size] = '\0';
        // 方法二 strcpy
        int len = strlen(str);
        if (len + _size > _capacity)
        {
            reserve(len + _size);
        }
        strncpy(_str + _size, str, len);
        _size += len;
    }
    string &append(size_t n, char c)
    {
        if (n + _size > _capacity)
        {
            reserve(n + _size);
        }
        for (size_t i = 0; i < n; i++)
        {
            _str[_size + i] = c;
        }
        _size += n;
        _str[_size] = '\0'; // 补补补
    }

4.5.3 operator[] ()

    string&operator+=(const string& str){//s1+="hello",,,,this指向的是s1
        append(str);
        return *this;
    }
    string&operator+=(const char*str){
        this->append(str);
        return *this;
    }
    string&operator+=(char ch){
        // append(1, ch);或者下面这个函数调用
        push_back(ch);
        return *this;
    }

4.5.4 push_back()

    void push_back(const char ch){
        if(_size==_capacity){
            reserve((_capacity == 0 ? 2 : 2 * _capacity));
        }
        _str[_size] = ch;
        _size += 1;
        _str[_size] = '\0';
    }

4.5.5 insert()

    void insert(size_t pos, const string &str)
    {
        assert(pos >= 0 && pos <= _capacity);
        size_t len = str._size;
        if (_size == _capacity)
        {
            reserve(len + _size);
        }
        // 数据挪动
        int end = _size;
        while (end >= pos)
        {
            _str[end + len] = _str[end];
            --end;
        }
        memcpy(_str + pos, str._str, len);
        _size += len;
        _str[_size] = '\0';
    }
    void insert(size_t pos, const char *str)
    {
        assert(pos >= 0 && pos <= _capacity);
        size_t len = strlen(str);
        size_t n = len + _size;
        if (_size == _capacity)
        {
            reserve(len + _size);
        }
        // 数据挪动
        for (size_t i = n; i >= pos + len; i--)
        {
            _str[i] = _str[i - len];
        }
        for (size_t i = 0; i < len; i++)
        {
            _str[pos + i] = str[i];
        }
    }
    void insert(size_t pos, size_t n, char c)
    {
        assert(pos >= 0 && pos < _size);
        if (_size + n > _capacity)
        {
            reserve(_size + n);
        }
        // 挪动数据
        for (size_t i = _size + n; i >= pos + n; i--)
            _str[i] = _str[i - n];
        for (size_t i = 0; i < n; i++)
            _str[pos + i] = c;
        _size += n;
        _str[_size] = '\0';
    }

4.5.6 erase()

    void erase(size_t pos, size_t len = npos) // npos
    {
        assert(pos >= 0 && pos < _size);
        if (len == npos)
            _str[0] = '\0';
        _size = 0;
        return;
        for (size_t i = pos; (len + i) < _size; i++)
            _str[i] = _str[i + len];
        _size -= len;
        _str[_size] = '\0';
    }

4.5.7 find()

    size_t find(const string &str, size_t pos = 0)
    {
        assert(pos >= 0 && pos < _size);
        char *tmp = strstr(_str + pos, str._str);
        if (tmp == nullptr)
        {
            return -1;
        }
        return tmp -_str;
    }

4.6 swap()

    void swap(string &str)
    {   //::表示全局域
        ::Swap(_str, str._str);
        ::Swap(_size, str._size);
        ::Swap(_capacity, str._capacity);
    }
//类外
template <typename T>
void Swap(T &x, T &y)
{
    T tmp = x;
    X = y;
    y = tmp;
}

4.6.1 现代写法改写operator[]

string& operator=(const string& str){
string tmp(str);//狸猫换太子
swap(tmp);
return *this;
}

串操作。。。流操作。。。

全部代码…

#include <iostream>
#include <string.h>
#include <assert.h>
using namespace std;

class string
{
public:
    string(const char *str = "") // 全缺省构造函数
        : _str(new char[strlen(str) + 1]), _size(0), _capacity(0)
    { // 深拷贝
        strcpy(_str, str);
    }
    string(const string &s) // 拷贝构造 string s1(s2);this指向s1被新创的对象
        : _str(new char[strlen(s._str) + 1])
    {
        strcpy(_str, s._str);
        _size = s._size;
        _capacity = s._capacity;
    }
    string(const char *s)
    {
        size_t len = strlen(s);
        _str = new char[len + 1];
        memcpy(_str, s, len + 1);
        _size = len;
        _capacity = len;
    }
    string(const char *s, size_t n)
    {
        int len = strlen(s);
        if (n > len)
        {
            n = len;
        }
        _str = new char[n + 1];
        memcpy(_str, s, n);
        *(_str + n) = '\0'; // 重,第n个位置补\0
        _size = n;
        _capacity = n;
    }
    string(size_t n, char c)
    {
        _str = new char[n + 1];
        for (size_t i = 0; i < n; i++)
        {
            _str[i] = c;
        }
        _str[n] = '\0';
        _size = n;
        _capacity = n;
    }
    string &operator=(const string &str) // s1=s2,s1是新的
    {
        if (this != &str)
        {
            char *tmp = new char[strlen(str._str) + 1];
            memcpy(tmp, str._str, strlen(str._str) + 1);
            delete[] _str;
            _str = tmp;
            _size = str._size;
            _capacity = str._capacity;
            return *this;
        }
    }
    //string& operator=(const string& str){
    // string tmp(str);
    // swap(tmp);
    // return *this;
    // }
    string &operator=(const char *s) // s1="ssssss"
    {
        delete[] _str;
        _str = new char[strlen(s) + 1];
        memcpy(_str, s, strlen(s) + 1);
        _size = _capacity = strlen(s);
        return *this;
    }
    string &operator=(char c) // s1='c'
    {
        delete[] _str;
        _str = new char[2];
        _str[0] = c;
        _str[1] = '\0';
        return *this;
    }
    void reserve(size_t n)
    { // 扩容
        if (n > _capacity)
        {
            // 开辟新空间
            char *tmp = new char[n + 1];
            memcpy(tmp, _str, _size);
            delete[] _str; // 释放旧空间
            _str = tmp;    // 指向新空间
            _capacity = n; // 改变现在容量
        }
    }
    void append(const string &str)
    { // 追加
        // 开辟新空间
        size_t len = str._size;
        if (len + _size > _capacity)
        {
            reserve(len + _size);
        }
        for (size_t i = 0; i < len; i++)
        {
            _str[_size + i] = str._str[i];
        }
        _size = len + _size;
        _str[_size] = '\0';
    }
    void append(const char *str)
    { // 字符串存在代码段
        // int len = strlen(s);
        // if (len+_size>_capacity)
        // {
        //     reserve(len + _size);
        // }
        // for (size_t i = 0; i < len;i++){
        //     _str[_size + i] = s[i];
        // }
        // _size = len + _size;
        // _str[_size] = '\0';
        // 方法二 strcpy
        int len = strlen(str);
        if (len + _size > _capacity)
        {
            reserve(len + _size);
        }
        strncpy(_str + _size, str, len);
        _size += len;
    }
    void append(size_t n, char c)
    {
        if (n + _size > _capacity)
        {
            reserve(n + _size);
        }
        for (size_t i = 0; i < n; i++)
        {
            _str[_size + i] = c;
        }
        _size += n;
        _str[_size] = '\0'; // 补补补
    }
    void push_back(const char ch)
    {
        if (_size == _capacity)
        {
            reserve((_capacity == 0 ? 2 : 2 * _capacity));
        }
        _str[_size] = ch;
        _size += 1;
        _str[_size] = '\0';
    }
    string &operator+=(const string &str)
    { // s1+="hello",,,,this指向的是s1
        append(str);
        return *this;
    }
    string &operator+=(const char *str)
    {
        this->append(str);
        return *this;
    }
    string &operator+=(char ch)
    {
        // append(1, ch);或者下面这个函数调用
        push_back(ch);
        return *this;
    }
    void insert(size_t pos, const string &str)
    {
        assert(pos >= 0 && pos <= _capacity);
        size_t len = str._size;
        if (_size == _capacity)
        {
            reserve(len + _size);
        }
        // 数据挪动
        int end = _size;
        while (end >= pos)
        {
            _str[end + len] = _str[end];
            --end;
        }
        memcpy(_str + pos, str._str, len);
        _size += len;
        _str[_size] = '\0';
    }
    void insert(size_t pos, const char *str)
    {
        assert(pos >= 0 && pos <= _capacity);
        size_t len = strlen(str);
        size_t n = len + _size;
        if (_size == _capacity)
        {
            reserve(len + _size);
        }
        // 数据挪动
        for (size_t i = n; i >= pos + len; i--)
        {
            _str[i] = _str[i - len];
        }
        for (size_t i = 0; i < len; i++)
        {
            _str[pos + i] = str[i];
        }
    }
    void insert(size_t pos, size_t n, char c)
    {
        assert(pos >= 0 && pos < _size);
        if (_size + n > _capacity)
        {
            reserve(_size + n);
        }
        // 挪动数据
        for (size_t i = _size + n; i >= pos + n; i--)
            _str[i] = _str[i - n];
        for (size_t i = 0; i < n; i++)
            _str[pos + i] = c;
        _size += n;
        _str[_size] = '\0';
    }

    void erase(size_t pos, size_t len = npos) // npos
    {
        assert(pos >= 0 && pos < _size);
        if (len == npos)
            _str[0] = '\0';
        _size = 0;
        return;
        for (size_t i = pos; (len + i) < _size; i++)
            _str[i] = _str[i + len];
        _size -= len;
        _str[_size] = '\0';
    }
    size_t find(const string &str, size_t pos = 0)
    {
        assert(pos >= 0 && pos < _size);
        char *tmp = strstr(_str + pos, str._str);
        if (tmp == nullptr)
        {
            return -1;
        }
        return tmp - _str;
    }
    void swap(string &str)
    { //::表示全局域
        ::Swap(_str, str._str);
        ::Swap(_size, str._size);
        ::Swap(_capacity, str._capacity);
    }
    int size()
    {
        return _size;
    }
    char &operator[](const int i)
    {
        return *(_str + i);
    }
    ~string()
    {
        _str = nullptr;
        delete[] _str;
        _capacity = _size = 0;
    }

private:
    char *_str;
    int _size;     // 已经有多少个有效字符
    int _capacity; // 能存多少个有效字符,   \0除外
};
template <typename T>
void Swap(T &x, T &y)
{
    T tmp = x;
    X = y;
    y = tmp;
}
int main()
{

    system("pause");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值