string类的模拟实现——模拟的技巧

news2025/1/13 11:52:39

前言

对于学习STL而言,最重要的手段之一就是亲手模拟实现一个自己的容器。string存储只为char类型,且操作上并没有很难的操作。因此对于初学者而言,string是一个很好的练手项目。

一、确定思路

虽说相对适合初学者模拟实现,但是string的规模也并不小,粗略也需要 300+ 行代码实现。因此在开始模拟实现之前一个完善的思维导图必不可少。下方给出一个简单的思维导图以及一个大体的框架

在这里插入图片描述

namespace hty {
    class string {
        friend ostream& operator<<(ostream& _cout, const hty::string& s);
        friend istream& operator>>(istream& _cin, hty::string& s);
    private:
        char* _str;
        size_t _capacity;
        size_t _size;
        const static size_t _npos = -1;
    public:
        typedef char* iterator;
        typedef const char* const_iterator;
    public:
        string(const char* str = "") 
        string(const string& s)
        string& operator=(const string& s)
        ~string()
        //
        
        // iterator
        iterator begin()
        iterator end()
        const iterator begin()const 
        const iterator end()const
        /
        
        // modify
        void push_back(char c) 
        void append(const char* str) 
        string& operator+=(char c) 
        string& operator+=(const char* str) 
        void clear() 
        void swap(string& s) 
        const char* c_str()const 
        /
        
        // capacity
        size_t size()const 
        size_t capacity()const
        bool empty()const 
        void resize(size_t n, char c = '\0') 
        void reserve(size_t n) 
        /
        
        // access
        char& operator[](size_t index) 
        const char& operator[](size_t index)const
        /
        
        //relational operators
        bool operator<(const string& s) 
        bool operator>(const string& s) 
        bool operator==(const string& s) 
        bool operator<=(const string& s) 
        bool operator>=(const string& s) 
        bool operator!=(const string& s) 

        // 返回c在string中第一次出现的位置
        size_t find(char c, size_t pos = 0) const 

        // 返回子串s在string中第一次出现的位置
        size_t find(const char* s, size_t pos = 0) const 

        // 在pos位置上插入字符c/字符串str
        string& insert(size_t pos, char c)
        string& insert(size_t pos, const char* str)

        // 删除pos位置上的元素,并返回该元素的下一个位置
        string& erase(size_t pos, size_t len = _npos) 
    };
};

二、实现过程

对于模拟实现,详细讲每个函数的实现过程显得冗杂,因此我将提出自己对于模拟实现的一些看法和实用性方法。

2.1 查阅文档

对于第一次模拟实现库来说,要学会多查阅文档,了解一个函数的返回值、功能是什么。同时了解该函数还能接受那些类型的传参,进行了哪些重载等,都十分重要。

2.2 验证正确性

在上面我们已经说到,模拟string库对于初学者来说也算一个不小的工作,因此在模拟过程中,必要的正确性验证是少不了的。每当我们完成一个或者多个功能相近的函数之后,我们首先要对这几个函数的正确性进行验证,而不是等到所有完成之后在验证。

过程中验证一方面能提高我们的动力,看到自己逐步实现的过程;另一方面有助于我们完成调试工作。等到所有函数完成之后,许多函数可能存在复用关系等,这样一来出现错误便不易定位,增大了调试的工作量。

2.3 测试案例

验证正确性过程中需要自己创建若干测试案例。对于测试案例的选取也是有很多要求的,要保证一些可能出现 bug 的位置也要测试到位。例如常见的对首元素、尾元素操作,对空字符串操作,对很大的字符串操作等。

三、完整代码

以下给出我的实现,如有错误欢迎指正:

namespace hty {
    class string {
        friend ostream& operator<<(ostream& _cout, const hty::string& s);
        friend istream& operator>>(istream& _cin, hty::string& s);
    private:
        char* _str;
        size_t _capacity;
        size_t _size;
        const static size_t _npos = -1;
    public:
        typedef char* iterator;
        typedef const char* const_iterator;
    public:
        string(const char* str = "") {
            _size = strlen(str);
            _str = new char[_size + 1];
            _capacity = _size;
            strcpy(_str, str);
        }

        string(const string& s) {
            _size = s.size();
            _capacity = _size;
            _str = new char[_size + 1];
            strcpy(_str, s.c_str());
        }

        string& operator=(const string& s) {
            if (this != &s) {
                resize(s.size());
                strcpy(_str, s.c_str());
            }
            return *this;
        }

        ~string() {
            _size = _capacity = 0;
            delete[] _str;
            _str = nullptr;
        }
        //
        
        // iterator
        iterator begin() {
            return _str;
        }

        iterator end() {
            return _str + _size;
        }

        const iterator begin()const {
            return _str;
        }

        const iterator end()const {
            return _str + _size;
        }
        /
        
        // modify
        void push_back(char c) {
            if (_size == _capacity) {
                size_t new_capacity = _capacity == 0 ? 4 : 2 * _capacity;
                reserve(new_capacity);
            }
            _str[_size] = c;
            _str[_size + 1] = 0;
            ++_size;
        }

        void append(const char* str) {
            size_t len = strlen(str);
            if (_size + len > _capacity)
                reserve(_capacity + len);
            strcpy(_str + _size, str);
            _size += len;
        }

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

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

        void clear() {
            _str[0] = 0;
            _size = 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 _size == 0;
        }
        
        void resize(size_t n, char c = '\0') {
            if (n > _capacity)
                reserve(n);
            if (n > _size) {
                for (size_t i = _size; i < n; i++)
                    _str[i] = c;
            }
            _str[n] = 0;
            _size = n;
        }

        void reserve(size_t n) {
            if (n > _capacity) {
                _capacity = n;
                char* tmp = new char[n + 1];
                strcpy(tmp, _str);
                delete[] _str;
                _str = tmp;
            }
        }
        /
        
        // access
        char& operator[](size_t index) {
            assert(index >= 0 && index <= _size);
            return _str[index];
        }

        const char& operator[](size_t index)const {
            assert(index >= 0 && index <= _size);
            return _str[index];
        }
        /
        
        //relational operators
        bool operator<(const string& s) {
            size_t len = max(s.size(), _size);
            for (size_t i = 0; i < len; i++) {
                if (_str[i] < s[i] || (_str[i] == 0 && s[i] != 0))
                    return true;
                else if (s[i] == 0)
                    return false;
            }
            return false;
        }

        bool operator>(const string& s) {
            size_t len = max(s.size(), _size);
            for (size_t i = 0; i < len; i++) {
                if (_str[i] > s[i] || (s[i] == 0 && s[i] != 0))
                    return true;
                else if (_str[i] == 0)
                    return false;
            }
            return false;
        }


        bool operator==(const string& s) {
            size_t len = max(s.size(), _size);
            for (size_t i = 0; i < len; i++) {
                if (_str[i] != s[i])
                    return false;
            }
            return true;
        }

        bool operator<=(const string& s) {
            return *this < s || *this == s;
        }
        bool operator>=(const string& s) {
            return *this > s || *this == s;
        }

        bool operator!=(const string& s) {
            return !(*this == s);
        }

        // 返回c在string中第一次出现的位置
        size_t find(char c, size_t pos = 0) const {
            assert(pos >= 0 && pos < _size);
            for (size_t i = pos; i < _size; i++) {
                if (_str[i] == c)
                    return i;
            }
            return _npos;
        }

        // 返回子串s在string中第一次出现的位置
        size_t find(const char* s, size_t pos = 0) const {
            assert(pos >= 0 && pos < _size);
            const char* ret = strstr(_str + pos, s);
            if (ret)
                return (ret - _str);
            else
                return _npos;
        }

        // 在pos位置上插入字符c/字符串str,并返回该字符的位置
        string& insert(size_t pos, char c) {
            assert(pos >= 0 && pos <= _size);
            if (_size == _capacity) {
                size_t new_capacity = _capacity == 0 ? 4 : 2 * _capacity;
                reserve(new_capacity);
            }
            for (size_t i = _size + 1; i > pos; i--)
                _str[i] = _str[i - 1];
            _str[pos] = c;
            _size++;
            return *this;
        }

        string& insert(size_t pos, const char* str) {
            assert(pos >= 0 && pos <= _size);
            size_t len = strlen(str);
            if (_size + len > _capacity) {
                size_t new_capacity = _size + len;
                reserve(new_capacity);
            }
            for (size_t i = _size + len; i > pos; i--)
                _str[i] = _str[i - len];
            strncpy(_str + pos, str, len);
            _size += len;
            return *this;
        }

        // 删除pos位置上的元素,并返回该元素的下一个位置
        string& erase(size_t pos, size_t len = _npos) {
            assert(pos >= 0 && pos < _size);
            if (len == _npos || pos + len >= _size) {
                _str[pos] = 0;
                _size = pos;
                return *this;
            }
            for (size_t i = pos; i <= _size - len; i++)
                _str[i] = _str[i + len];
            _size -= len;
            return *this;
        }
    };

    ostream& operator<<(ostream& _cout, const hty::string& s) {
        for (size_t i = 0; i < s.size(); i++) {
            _cout << s[i];
        }
        return _cout;
    }

    istream& operator>>(istream& _cin, hty::string& s) {
        char ch = '0', buff[128] = { 0 };
        s.clear();
        int i = 0;
        while (ch = _cin.get()) {
            if (ch != ' ' && ch != '\n') {
                buff[i++] = ch;
                if (i == 127){
                    s += buff;
                    i = 0;
                }
            }
            else {
                buff[i] = 0;
                s += buff;
                break;
            }
        }
        return _cin;
    }
};

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

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

相关文章

.net 7 隐藏swagger的api

1.写一个隐藏接口特性表示 using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen;using System.Web.Http.Description;namespace JiaTongInterface.Filter {public class SwaggerApi : Swashbuckle.AspNet…

信息系统项目管理教程(第4版):第二章 信息技术及其发展

请点击↑关注、收藏&#xff0c;本博客免费为你获取精彩知识分享&#xff01;有惊喜哟&#xff01;&#xff01; 第二章 信息技术及其发展 2.1信息技术及其发展 信息技术是以微电子学为基础的计算机技术和电信技术的结合而形成的&#xff0c;对声音的、图像的、文字的、数字…

觉非科技数据闭环系列 | BEV感知研发实践

随着自动驾驶迈向量产场景&#xff0c;“BEV感知数据闭环”已成为新一代自动驾驶量产系统的核心架构。数据成为了至关重要的技术驱动力&#xff0c;发挥数据闭环的飞轮效应或将成为下半场从1到N的胜负关键。 觉非科技在此方面已进行了大量的研究工作&#xff0c;并在实际量产项…

【LeetCode-简单题】69. x 的平方根

文章目录 题目方法一&#xff1a;二分查找 题目 方法一&#xff1a;二分查找 假设求8的平方根&#xff0c;那就设置left 0 &#xff0c;right 8&#xff1b; 每次取最中间的元素的平方和8对比&#xff0c;如果大于8&#xff0c;则right mid-1&#xff0c;如果小于8 left mi…

大数据是什么?看完这个就明白了【电商大数据分析与电商API】

什么是大数据&#xff1f; 在互联网技术发展到至今阶段&#xff0c;大量日常、工作等事务产生的数据都已经信息化&#xff0c;人类产生的数据量相比以前有了爆炸式的增长&#xff0c;以前传统的数据处理技术已经无法胜任&#xff0c;需求催生技术&#xff0c;一套用来处理海量数…

PIONEER MAGNETICS PM3326B-6-1-2-E 80026-529-01 电源

输出功率&#xff1a;该电源模块通常具有特定的输出功率&#xff0c;用于供电其他设备和系统。输出功率可能在规格表中列出。 电压和电流范围&#xff1a;通常&#xff0c;该电源模块可以提供一定范围内的输出电压和电流&#xff0c;以满足不同设备的需求。这些参数通常在技术…

迅为i.MX8mm小尺寸商业级/工业级核心板

尺寸&#xff1a; 50mm*50mm CPU&#xff1a; NXP i.MX8M Mini 主频&#xff1a; 1.8GHz 架构&#xff1a; 四核Cortex-A53&#xff0c;单核Cortex-M4 PMIC&#xff1a; PCA9450A电源管理PCA9450A电源管理NXP全新研制配&#xff0c;iMX8M的电源管理芯片有六个降压稳压器、五…

C语言经典100例题(44)--学习使用extern的用法。

目录 题目 问题分析 代码 运行结果 题目 题目&#xff1a;学习使用extern的用法。 问题分析 extern int i&#xff1b; //定义全局变量 i 上述代码语句&#xff0c;extern告诉编译器&#xff0c;变量i是在程序中的其他位置定义的&#xff08;很有可能是在不同的源文件中…

自定义Dynamics 365实施和发布业务解决方案 - 7. 报表

在每个组织中,决策者都依赖于各种报告来推动业务取得成功。因此,每个软件开发项目都需要开发报告,Dynamics365配备了最先进的报告功能。这些报告的范围从简单的查询到具有复杂查询的更高级的报告。此外,Dynamics365的一个关键功能是其仪表板功能,它提供了一些不错的数据可…

防雷检测综合技术方案

雷电是一种自然现象&#xff0c;具有极高的电压、电流和能量&#xff0c;对人类的生命财产安全构成严重威胁。为了有效地防止或减轻雷电灾害的危害&#xff0c;建筑物需要安装合理的防雷装置&#xff0c;以拦截或引导雷电流&#xff0c;保护建筑物内部的人员和设备。然而&#…

戳泡泡小游戏

欢迎来到程序小院 戳泡泡 玩法&#xff1a; 鼠标点击上升的起泡泡&#xff0c;点击暴躁记录分数&#xff0c;不要让泡泡越过屏幕&#xff0c;共有三次复活生命&#xff0c;会有随机星星出现&#xff0c;点击即可暴躁全屏哦^^。开始游戏https://www.ormcc.com/play/gameStart/1…

【笔试强训选择题】Day39.习题(错题)解析

作者简介&#xff1a;大家好&#xff0c;我是未央&#xff1b; 博客首页&#xff1a;未央.303 系列专栏&#xff1a;笔试强训选择题 每日一句&#xff1a;人的一生&#xff0c;可以有所作为的时机只有一次&#xff0c;那就是现在&#xff01;&#xff01;&#xff01;&#xff…

深圳寄墨西哥专线国际快递详解

随着全球贸易的不断发展&#xff0c;国际快递服务的需求也越来越大。深圳这座中国的特区城市&#xff0c;不仅是全球电子产品供应链的重要节点&#xff0c;也是国际快递服务的中心之一。对于那些需要将物品从深圳邮寄到墨西哥的人来说&#xff0c;深圳邮寄到墨西哥专线是他们不…

记录在windows下安装MySQL所遇到的各种坑

1.下载 从官网下载installer 然后开始选择要安装的组件 安装了很久进度都是0&#xff0c;无奈点击show detail以后发现&#xff0c;webclient异常&#xff0c;最后是将链接地址复制到迅雷才成功下载的 等迅雷下载完成以后&#xff0c;会看到有如下2个新msi文件 msi都是windows…

手机照片怎么拼图?分享几种拼图小技巧

当我们有很多照片想要展示&#xff0c;但是单独的每一张照片都不足以表达我们想要传达的信息时&#xff0c;我们会把这些照片拼在一起&#xff0c;以形成一张照片墙或者一张拼贴画。这样不仅可以更好地展示我们想要表达的内容&#xff0c;还可以在视觉上创造出更多的艺术效果和…

100个ArcGIS属性查询公式

这里说的ArcGIS属性查询公式&#xff0c;其本质是在ArcMap中通过属性分析查询数据时&#xff0c;为数据库的SQL查询语句构建查询条件。 因此&#xff0c;这里所谓的查询公式&#xff0c;其实是查询条件&#xff0c;希望它能在你处理地图数据的工作中&#xff0c;为你提升些许工…

微服务架构的现状与未来:服务网格与云原生趋势解析

文章目录 微服务架构的崛起服务网格的崭露Istio和EnvoyLinkerd 云原生技术的崭露KubernetesHelm 未来趋势更强大的服务网格更智能的自动化更紧密的云原生集成 结论 &#x1f389;欢迎来到AIGC人工智能专栏~微服务架构的现状与未来&#xff1a;服务网格与云原生趋势解析 ☆* o(≧…

(十一)Springboot+ElasticSearch8整合

前言 在 Elasticsearch7.15版本之后&#xff0c;Elasticsearch官方将它的高级客户端 RestHighLevelClient标记为弃用状态。推出全新的 Java API客户端 Elasticsearch Java API Client&#xff0c;该客户端也将在 Elasticsearch8.0及以后版本中成为官方推荐使用的客户端。 1.导…

【nosql】redis之高可用(主从复制、哨兵、集群)搭建

redis群集有三种模式 redis群集有三种模式&#xff0c;分别是主从同步/复制、哨兵模式、Cluster集群&#xff0c;下面会讲解一下三种模式的工作方式&#xff0c;以及如何搭建cluster群集 ●主从复制&#xff1a;主从复制是高可用Redis的基础&#xff0c;哨兵和集群都是在主从…

c#查看代码的执行耗时( Stopwatch )

我们如果需要看某段代码的执行耗时&#xff0c;会通过如下的方式进行查看 using System.Diagnostics; private void button1_Click(object sender, EventArgs e){Stopwatch sw Stopwatch.StartNew();//sw.Start();StringBuilder sb new StringBuilder();for(int i 0; i <…