【C++】string的底层剖析以及模拟实现

简介: 【C++】string的底层剖析以及模拟实现

一、字符串类的认识

       C语言中,字符串是以'\0'结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数, 但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。在OJ中,有关字符串的题目基本以string类的形式出现,而且在常规工作中,为了简单、方便、快捷,基本 都使用string类,很少有人去使用C库中的字符串操作函数。为了增加自己对于string的理解,自己将模仿库中string类有的方法,设计一个简单的string类。其中类成员包括以下:

class string
    {
    private:
        char* _str;//字符串首地址
        size_t _capacity;//字符串容量
        size_t _size;//有效数据的个数
    public:
        typedef char* iterator;
    }

二、库中string常用的方法

       我主要会实现string中经常会用到的方法,若大家想要了解更多关于string的细节,可以登录这个C++查询网站https://cplusplus.com/reference/自行查询下面是一些常用方法以及代码片段,可能前面出现的方法会用到后面出现的方法的实现,若有疑问可以看最后面的完整代码

正向迭代器

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

+=

string& operator+=(char c)
        {
            if (_size == _capacity)
            {
                _capacity = _capacity == 0 ? 4 : 2 * _capacity;
                char* tmp = new char[_capacity +1];
                strcpy(tmp, _str);
                delete[] _str;
                _str = tmp;
            }
            _str[_size] = c;
            _str[_size + 1] = '\0';
            _size++;
            return *this;
        }
        string& operator+=(const char* str)
        {
            append(str);
            return *this;
        }

push_back(尾插)

void push_back(char c)
        {
            *this += c;
        }

append(在字符串末尾追加)

void append(const char* str)
        {
            int i = 0;
            while (str[i])
            {
                push_back(str[i]);
                i++;
            }
        }

 clear(清除掉字符串的数据)

void clear()
        {
            _size = 0;
            _str[0] = '\0';
        }

  swap(交换两个字符串的内容)

void swap(string& s)
        {
            std::swap(_str,s._str);
            std::swap(_size, s._size);
            std::swap(_capacity, s._capacity);
        }

 c_str(返回字符串的首地址)

const char* c_str()const
        {
            return _str;
        }

resize(将字符串设定为指定大小,字符串占满所开辟的空间)

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

reserve(预开辟出空间,字符串还是原来的大小(一般不缩容))

void reserve(size_t n)
        {
            if (n > _capacity)
            {
                _capacity = n;
                char* tmp = new char[_capacity + 1];
                strcpy(tmp, _str);
                delete[] _str;
                _str = tmp;
            }
        }

 find(返回字符c在string中第一次出现的位置/返回子串s在string中第一次出现的位置

size_t find(char c, size_t pos = 0) const
        {
            for (size_t i = pos; i < _size; i++)
            {
                if (_str[i] == c)
                    return i;
            }
            return std::string::npos;
        }
        size_t find(const char* s, size_t pos = 0) const
        {
            const char* ptr = std::strstr(_str + pos, s);
            if (ptr == nullptr)
                return std::string::npos;
            else
            {
                return ptr - _str;
            }
        }

insert(在pos位置上插入字符c/字符串str,并返回该字符的位置)

string& insert(size_t pos, char c)
        {
            if (_size == _capacity)
            {
                reserve(_capacity == 0 ? 4 : 2 * _capacity);
            }
            size_t end = _size - 1;
            while (end >= pos)
            {
                _str[end + 1] = _str[end];
                end--;
            }
            _str[pos] = c;
            return *this;
        }
        string& insert(size_t pos, const char* str)
        {
            int len = 0;
            while (str[len++]);
            if (_size + len > _capacity)
            {
                reserve(_size + len);
            }
            memmove(_str + pos + len, _str + pos, len * sizeof(char));
            for (int i = pos; i < pos + len; i++)
            {
                _str[i] = str[i - pos];
            }
            _size += len;
            return *this;
        }

erase(删除pos位置上的元素,并返回该string)

string& erase(size_t pos, size_t len)
        {
            memmove(_str + pos, _str + pos + len, (_size - pos-len) * sizeof(char));
            _size -= len;
            return *this;
        }

三、完整代码

//string.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string>
//using namespace std;
namespace sxb
{
    class string
    {
        friend std::ostream& operator<<(std::ostream& _cout, const string& s);
        friend std::istream& operator>>(std::istream& _cin, string& s);
    private:
        char* _str;
        size_t _capacity;
        size_t _size;
    public:
        typedef char* iterator;
    public:
        string(const char* str = "")
        {
            //_str = str;
            int len = 0;
            while(str[len] != ' ' && str[len] != '\0')
            {
                len++;
            }
            _str = new char[len + 1];
            for (int i = 0; i < len; i++)
            {
                _str[i] = str[i];
            }
            _str[len] = '\0';
            _capacity = len;
            _size = len;
        }
        string(const string& s)
        {
            _str = new char[s.size() + 1];
            strcpy(_str, s.c_str());
            _str[s.size()] = '\0';
            _capacity = s.size();
            _size = s.size();
        }
        string& operator=(const string& s)
        {
            for (int i = 0; i < size(); i++)
            {
                _str += s[i];
            }
            return *this;
        }
        ~string()
        {
            delete[] _str;
            _size = 0;
            _capacity = 0;
        }
            //
            // iterator
        iterator begin()
        {
            return _str;
        }
        iterator end()
        {
            return _str + _size;
        }
        //    /
        //    // modify
        void push_back(char c)
        {
            *this += c;
        }
        string& operator+=(char c)
        {
            if (_size == _capacity)
            {
                _capacity = _capacity == 0 ? 4 : 2 * _capacity;
                char* tmp = new char[_capacity +1];
                strcpy(tmp, _str);
                delete[] _str;
                _str = tmp;
            }
            _str[_size] = c;
            _str[_size + 1] = '\0';
            _size++;
            return *this;
        }
        void append(const char* str)
        {
            int i = 0;
            while (str[i])
            {
                push_back(str[i]);
                i++;
            }
        }
        string& operator+=(const char* str)
        {
            append(str);
            return *this;
        }
        void clear()
        {
            _size = 0;
            _str[0] = '\0';
        }
        void swap(string& s)
        {
            std::swap(_str,s._str);
            std::swap(_size, s._size);
            std::swap(_capacity, s._capacity);
        }
        const char* c_str()const
        {
            return _str;
        }
        ///
         capacity
        size_t size()const
        {
            return _size;
        }
        size_t capacity()const
        {
            return _capacity;
        }
        bool empty()const
        {
            return _str[0] == '\0';
        }
        void resize(size_t n, char c = '\0')
        {
            if (n > _capacity)
            {
                reserve(n);
                for (int i = _size; i < _capacity; i++)
                {
                    _str[i] = c;
                }
                _size = _capacity;
            }
            else
            {
                _size = n;
            }
        }
        void reserve(size_t n)
        {
            if (n > _capacity)
            {
                _capacity = n;
                char* tmp = new char[_capacity + 1];
                strcpy(tmp, _str);
                delete[] _str;
                _str = tmp;
            }
        }
        ///
         access
        char& operator[](size_t index)
        {
            return _str[index];
        }
        const char& operator[](size_t index)const
        {
            return _str[index];
        }
        ///
        relational operators
        bool operator==(const string& s)
        {
            if (_size != s.size())
                return false;
            for (int i = 0; i < _size; i++)
            {
                if (_str[i] != s[i])
                    return false;
            }
            return true;
        }
        bool operator!=(const string& s)
        {
            return !operator==(s);
        }
         返回c在string中第一次出现的位置
        size_t find(char c, size_t pos = 0) const
        {
            for (size_t i = pos; i < _size; i++)
            {
                if (_str[i] == c)
                    return i;
            }
            return std::string::npos;
        }
         返回子串s在string中第一次出现的位置
        size_t find(const char* s, size_t pos = 0) const
        {
            const char* ptr = std::strstr(_str + pos, s);
            if (ptr == nullptr)
                return std::string::npos;
            else
            {
                return ptr - _str;
            }
        }
         在pos位置上插入字符c/字符串str,并返回该字符的位置
        string& insert(size_t pos, char c)
        {
            if (_size == _capacity)
            {
                reserve(_capacity == 0 ? 4 : 2 * _capacity);
            }
            size_t end = _size - 1;
            while (end >= pos)
            {
                _str[end + 1] = _str[end];
                end--;
            }
            _str[pos] = c;
            return *this;
        }
        string& insert(size_t pos, const char* str)
        {
            int len = 0;
            while (str[len++]);
            if (_size + len > _capacity)
            {
                reserve(_size + len);
            }
            memmove(_str + pos + len, _str + pos, len * sizeof(char));
            for (int i = pos; i < pos + len; i++)
            {
                _str[i] = str[i - pos];
            }
            _size += len;
            return *this;
        }
         删除pos位置上的元素,并返回该元素的下一个位置
        string& erase(size_t pos, size_t len)
        {
            memmove(_str + pos, _str + pos + len, (_size - pos-len) * sizeof(char));
            _size -= len;
            return *this;
        }
    };
    std::ostream& operator<<(std::ostream& _cout, const string& s)
    {
        for (int i = 0; i < s.size(); i++)
        {
            _cout << s[i];
        }
        return _cout;
    }
    std::istream& operator>>(std::istream& _cin, string& s)
    {
        char buffer[128];
        int len = 0;
        char bu = _cin.get();
        while (bu != ' ' && bu != '\n')
        {
            buffer[len] = bu;
            len++;
            bu = _cin.get();
        }
        for (int i = 0; i < len; i++)
        {
            s += buffer[i];
        }
        return _cin;
    }
}
相关文章
|
25天前
|
C语言 C++ 容器
【c++丨STL】string模拟实现(附源码)
本文详细介绍了如何模拟实现C++ STL中的`string`类,包括其构造函数、拷贝构造、赋值重载、析构函数等基本功能,以及字符串的插入、删除、查找、比较等操作。文章还展示了如何实现输入输出流操作符,使自定义的`string`类能够方便地与`cin`和`cout`配合使用。通过这些实现,读者不仅能加深对`string`类的理解,还能提升对C++编程技巧的掌握。
52 5
|
25天前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
38 2
|
2月前
|
C++ 容器
|
2月前
|
存储 安全 C++
【C++打怪之路Lv8】-- string类
【C++打怪之路Lv8】-- string类
26 1
|
2月前
|
C++ 容器
|
2月前
|
C++ 容器
|
2月前
|
存储 C++ 容器
|
2月前
|
安全 C语言 C++
【C++篇】探寻C++ STL之美:从string类的基础到高级操作的全面解析
【C++篇】探寻C++ STL之美:从string类的基础到高级操作的全面解析
46 4
|
2月前
|
存储 编译器 程序员
【C++篇】手撕 C++ string 类:从零实现到深入剖析的模拟之路
【C++篇】手撕 C++ string 类:从零实现到深入剖析的模拟之路
75 2
|
2月前
|
编译器 C语言 C++
【C++】C++ STL 探索:String的使用与理解(三)
【C++】C++ STL 探索:String的使用与理解