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

news2024/9/28 15:30:48

一、字符串类的认识

        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;
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1516847.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

算法空间复杂度计算

目录 空间复杂度定义 影响空间复杂度的因素 算法在运行过程中临时占用的存储空间讲解 例子 斐波那契数列递归算法的性能分析 二分法&#xff08;递归实现&#xff09;的性能分析 空间复杂度定义 空间复杂度(Space Complexity)是对一个算法在运行过程中临时占用存储空间大…

深入理解JAVA异常(自定义异常)

目录 异常的概念与体系结构 异常的概念&#xff1a; 异常的体系结构&#xff1a; 异常的分类&#xff1a; 异常的处理 防御式编程 LBYL: EAFP: 异常的抛出 异常的捕获 异常声明throws try-catch捕获并处理 finally 面试题&#xff1a; 异常的处理流程 异常处…

【数据结构与算法】:插入排序与希尔排序

&#x1f525;个人主页&#xff1a; Quitecoder &#x1f525;专栏: 数据结构与算法 欢迎大家来到初阶数据结构的最后一小节&#xff1a;排序 目录 1.排序的基本概念与分类1.1什么是排序的稳定性&#xff1f;1.2内排序与外排序内排序外排序 2.插入排序2.1实现插入排序2.3稳定性…

谈谈你对Java平台的理解?

从你接触 Java 开发到现在&#xff0c;你对 Java 最直观的印象是什么呢&#xff1f;是它宣传的 “Write once, run anywhere”&#xff0c;还是目前看已经有些过于形式主义的语法呢&#xff1f;你对于 Java 平台到底了解到什么程度&#xff1f;请你先停下来总结思考一下。 今天…

【DAY11 软考中级备考笔记】数据结构 排序操作系统

数据结构 排序&&操作系统 3月14日 – 天气&#xff1a;晴 今天天气非常热&#xff0c;已经到20度了&#xff0c;春天已经来了。 1. 堆排序 堆排序的思想是首先建立一个堆&#xff0c;然后弹出堆顶元素&#xff0c;剩下的元素再形成一个堆&#xff0c;然后继续弹出元素&…

计算机视觉研究院 | EdgeYOLO:边缘设备上实时运行的目标检测器及Pytorch实现

本文来源公众号“计算机视觉研究院”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;EdgeYOLO&#xff1a;边缘设备上实时运行的目标检测器及Pytorch实现 代码地址&#xff1a;https://github.com/LSH9832/edgeyolo 今天分享的研究…

【Python】使用plt库绘制动态曲线图,并导出为GIF或MP4

一、绘制初始图像 正常使用plt进行绘图&#xff0c;这里举例一个正弦函数&#xff1a; 二、绘制动态图的每一帧 思路&#xff1a; 根据横坐标点数绘制每一帧画面每次在当前坐标处&#xff0c;绘制一个点和垂直的线&#xff0c;来表示当前点可以在点上加个坐标等样式来增加…

ENISA 2023年威胁态势报告:主要发现和建议

欧盟网络安全局(ENISA)最近发布了其年度2023年威胁态势报告。该报告确定了预计在未来几年塑造网络安全格局的主要威胁、主要趋势、威胁参与者和攻击技术。在本文中&#xff0c;我们将总结报告的主要发现&#xff0c;并提供可操作的建议来缓解这些威胁。 介绍 ENISA 威胁态势报告…

基于SSM的网上医院预约挂号系统的设计与实现(论文+源码)_kaic

摘 要 如今的信息时代&#xff0c;对信息的共享性&#xff0c;信息的流通性有着较高要求&#xff0c;因此传统管理方式就不适合。为了让医院预约挂号信息的管理模式进行升级&#xff0c;也为了更好的维护医院预约挂号信息&#xff0c;网上医院预约挂号系统的开发运用就显得很…

linux系统网络配置

文章目录 Linux系统配置IPLinux系统配置DNSLinux网卡名称命名CentOS7密码重置远程管理Linux服务器 前文我们了解如何启动linux系统&#xff0c;接下来我们继续学习如何配置linux系统的网络&#xff0c;同时也是学习一下Centos 7 系统的密码重置以及借用工具远程链接服务器 Lin…

Python二级备考

考试大纲如下&#xff1a; 基本要求 考试内容 考试方式 比较希望能直接刷题&#xff0c;因为不懂的比较多可能会看视频。 基础操作刷题&#xff1a; 知乎大头计算机1-13题 import jieba txtinput() lsjieba.lcut(txt) print("{:.1f}".format(len(txt)/len(ls)…

WorldGPT、Pix2Pix-OnTheFly、StyleDyRF、ManiGaussian、Face SR

本文首发于公众号&#xff1a;机器感知 WorldGPT、Pix2Pix-OnTheFly、StyleDyRF、ManiGaussian、Face SR HandGCAT: Occlusion-Robust 3D Hand Mesh Reconstruction from Monocular Images We propose a robust and accurate method for reconstructing 3D hand mesh from m…

Selenium 学习(0.20)——软件测试之单元测试

我又&#xff08;浪完&#xff09;回来了…… 很久没有学习了&#xff0c;今天忙完终于想起来学习了。没有学习的这段时间&#xff0c;主要是请了两个事假&#xff08;5工作日和10工作日&#xff09;放了个年假&#xff08;13天&#xff09;&#xff0c;然后就到现在了。 看了下…

每周一算法:A*(A Star)算法

八数码难题 题目描述 在 3 3 3\times 3 33 的棋盘上&#xff0c;摆有八个棋子&#xff0c;每个棋子上标有 1 1 1 至 8 8 8 的某一数字。棋盘中留有一个空格&#xff0c;空格用 0 0 0 来表示。空格周围的棋子可以移到空格中。要求解的问题是&#xff1a;给出一种初始布局…

微信小程序购物/超市/餐饮/酒店商城开发搭建过程和需求

1. 商城开发的基本框架 a. 用户界面&#xff08;Frontend&#xff09; 页面设计&#xff1a;包括首页、商品列表、商品详情、购物车、下单界面、用户中心等。交云设计&#xff1a;如何让用户操作更加流畅&#xff0c;包括搜索、筛选、排序等功能的实现。响应式设计&#xff1…

【JAVA重要知识 | 第六篇】Java集合类使用总结(List、Set、Map接口及常见实现类)以及常见面试题

文章目录 6.Java集合类使用总结6.1概览6.1.1集合接口类特性6.1.2List接口和Set接口的区别6.1.3简要介绍&#xff08;1&#xff09;List接口&#xff08;2&#xff09;Set接口&#xff08;3&#xff09;Map接口 6.2Collection接口6.3List接口6.3.1ArrayList6.3.2LinkedList—不常…

网络模块使用Hilt注入

retrofit的异步回调方法已经做了线程切换&#xff0c;切换到了主线程 <?xml version"1.0" encoding"utf-8"?> <manifest xmlns:android"http://schemas.android.com/apk/res/android"><uses-permission android:name"andr…

Solidity 智能合约开发 - 基础:基础语法 基础数据类型、以及用法和示例

苏泽 大家好 这里是苏泽 一个钟爱区块链技术的后端开发者 本篇专栏 ←持续记录本人自学两年走过无数弯路的智能合约学习笔记和经验总结 如果喜欢拜托三连支持~ 本篇主要是做一个知识的整理和规划 作为一个类似文档的作用 更为简要和明了 具体的实现案例和用法 后续会陆续给出…

Milvus向量数据库检索

官方文档&#xff1a;https://milvus.io/docs/search.md   本节介绍如何使用 Milvus 搜索实体。   Milvus 中的向量相似度搜索会计算查询向量与具有指定相似度度量的集合中的向量之间的距离&#xff0c;并返回最相似的结果。您可以通过指定过滤标量字段或主键字段的布尔表达…

Redis及其数据类型和常用命令(一)

Redis 非关系型数据库&#xff0c;不需要使用sql语句对数据库进行操作&#xff0c;而是使用命令进行操作&#xff0c;在数据库存储时使用键值对进行存储&#xff0c;应用场景广泛&#xff0c;一般存储访问频率较高的数据。 一般关系型数据库&#xff08;使用sql语句进行操作的…