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

}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[LeetCode][110]平衡二叉树

题目 110.平衡二叉树 给定一个二叉树&#xff0c;判断它是否是平衡二叉树。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;true 示例 2&#xff1a; 输入&#xff1a;root [1,2,2,3,3,null,null,4,4] 输出&#xff1a;false 示例 3&…

ROS 语音交互(三) tts

目录 一、模型选择 二、流程 三、核心代码展示 一、模型选择 科大讯飞超拟人识别 二、流程 超拟⼈合成协议 | 讯飞开放平台文档中心 (xfyun.cn) 三、核心代码展示 # coding: utf-8 import _thread as thread import os import time import base64import base64 import …

一种基于宏和serde_json实现的rust web中统一返回类

本人rust萌新&#xff0c;写web碰到了这个&#xff0c;基于ChatGPT和文心一言学了宏&#xff0c;强行把这玩意实现出来了&#xff0c;做个学习记录&#xff0c;如果有更好的方法&#xff0c;勿喷。 先看效果&#xff0c;注意不支持嵌套&#xff0c;且kv映射要用>(因为它这个…

【LeetCode热题100】142. 环形链表 II(链表)

一.题目要求 给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统…

C++初阶:类和对象(三)——拷贝构造函数和运算符重载

目录 一、拷贝构造函数 1.概念 2.特性 二、赋值运算符重载 1.运算符重载 2.赋值运算符重载 &#xff08;1&#xff09;注意的点&#xff1a; &#xff08;2&#xff09;赋值运算符不允许被重载为全局函数&#xff0c;只能重载为类的成员函数 &#xff08;3&#xff09;…

C语言例3-11:使用算术运算符的例子。

代码如下&#xff1a; int main(void) {int a12, b10;float c2.0, d0.5;double e6.5, f13.0;printf("-a %d\n",-a);printf("ab %d\n",ab);printf("a-b %d\n",a-b);printf("a*b %d\n",a*b);printf("a/b %d\n"…

RabbitMq踩坑记录

1、连接报错&#xff1a;Broker not available; cannot force queue declarations during start: java.io.IOException 2.1、原因&#xff1a;端口不对 2.2、解决方案&#xff1a; 检查你的连接配置&#xff0c;很可能是你的yml里面的端口配置的是15672&#xff0c;更改为5672即…

Python实时追踪关键点组成人体模型

项目背景 最近遇到这样一个需求&#xff1a; 1&#xff1a;实时追踪关键点组成人体模型&#xff08;手臂包括三个点&#xff1a;手腕&#xff0c;肘关节&#xff0c;双肩&#xff1b;腿部包括胯骨&#xff0c;膝盖&#xff0c;脚踝&#xff09; 2&#xff1a;运用追踪到的关键…

15.WEB渗透测试--Kali Linux(三)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;14.WEB渗透测试--Kali Linux&#xff08;二&#xff09;-CSDN博客 Kali工具使用 3389远…

基于springboot+vue实现电子商务平台管理系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现电子商务平台管理系统演示 研究的目的和意义 据我国IT行业发布的报告表明&#xff0c;近年来&#xff0c;我国互联网发展呈快速增长趋势&#xff0c;网民的数量已达8700万&#xff0c;逼近世界第一&#xff0c;并且随着宽带的实施及降价&#xff0c;每天约有…

【数据结构】树与堆 (向上/下调整算法和复杂度的分析、堆排序以及topk问题)

文章目录 1.树的概念1.1树的相关概念1.2树的表示 2.二叉树2.1概念2.2特殊二叉树2.3二叉树的存储 3.堆3.1堆的插入&#xff08;向上调整&#xff09;3.2堆的删除&#xff08;向下调整&#xff09;3.3堆的创建3.3.1使用向上调整3.3.2使用向下调整3.3.3两种建堆方式的比较 3.4堆排…

从0开始做知乎好物

一、什么是知乎好物 是知乎官方推出的一种帮助内容创作者变现的方式&#xff0c;以图文的形式为主&#xff0c;在创作的内容当中插入相关的商品卡片&#xff0c;用户通过点击卡片链接购买后&#xff0c;会有一定比例的佣金给到创作者 是指在知乎社区中推荐或被推荐的一些高品…

es 聚合操作(二)

书接上文&#xff0c;示例数据在上一篇&#xff0c;这里就不展示了 一、Pipeline Aggregation 支持对聚合分析的结果&#xff0c;再次进行聚合分析。 Pipeline 的分析结果会输出到原结果中&#xff0c;根据位置的不同&#xff0c;分为两类&#xff1a; Sibling - 结果和现有…

OD_2024_C卷_200分_4、二叉树计算【JAVA】【二叉树前序、中序遍历】

代码 package odjava;import java.util.*;public class 四_二叉树计算 {static class TreeNode {int num; // 当前节点的值int childSum; // 当前节点的左子树右子树的和TreeNode leftChild;TreeNode rightChild;public TreeNode(int num) {this.num num;this.childSum 0;th…

嵌入式常用5种通信协议

简介&#xff1a; 嵌入式常用五种通信协议为&#xff1a;UART、RS232、RS485、IIC、SPI。 由于这几种通信协议十分相似又有区别&#xff0c;所以分组记忆&#xff0c;红色的为一组&#xff0c;蓝色的为一组。 ①组都有两条线&#xff0c;且都是异步通信没得时钟线&#xff0c…

基于springboot校园资产管理系统

现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本校园资产管理就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据信息&#xff0…

Baumer工业相机堡盟工业相机如何通过NEOAPISDK实现双快门采集两张曝光时间非常短的图像(C++)

Baumer工业相机堡盟工业相机如何通过NEOAPISDK实现双快门采集两张曝光时间非常短的图像&#xff08;C&#xff09; Baumer工业相机Baumer工业相机定序器功能的技术背景Baumer工业相机通过NEOAPI SDK使用定序器功能预期的相机动作技术限制定序器的工作原理 Baumer工业相机通过NE…

缩写

解法&#xff1a; 看字符串首元素即可 #include<iostream> #include<vector> #include<string> #include<sstream> using namespace std; #define endl \n void solve() {cin >> ws;string s, str;getline(cin, s);stringstream ss(s);while (…

Pretrain-finetune、Prompting、Instruct-tuning训练方法的区别

来自&#xff1a;【多模态】28、LLaVA 第一版 | Visual Instruction Tuning 多模态模型的指令微调_多模态指令跟随数据-CSDN博客 几种模型训练方法的区别&#xff1a; 1、Pretrain-finetune&#xff1a;先在大量数据集上做预训练&#xff0c;然后针对某个子任务做 finetune 2…

11GR2 rac 2节点一键安装演示

Oracle 一键安装脚本&#xff0c;演示 2 节点 RAC 一键安装过程&#xff08;全程无需人工干预&#xff09;&#xff1a;&#xff08;脚本包括 GRID/ORALCE PSU/OJVM 补丁自动安装&#xff09; ⭐️ 脚本下载地址&#xff1a;Shell脚本安装Oracle数据库 脚本第三代支持 N 节点…
最新文章