string 的模拟实现

 

string 的相关介绍:C++:string相关内容的简单介绍-CSDN博客

成员变量:

private:
  char* _str
  size_t _size
  size_t _capacity

 构造函数

string类的构造函数不仅需要完成空间的开辟,还需要再开辟的过程中完成字符串的拷贝,它需要将字符串拷贝到空间的内部

以此string类的构造函数需要strlen和new的帮助,使用二者来获取长度和空间,并进行一系列的赋值操作。 

string (const char*str = "")
    :_size(strlen(str))
{  
    _capacity = _size;
    _str = new char[_capacity + 1];
   strcpy(_str,str);

}

以上的代码设立了缺省值为空,表名了这是一个即是无参又是有参的一个构造函数。

设立缺省值为空的好处在于,当传递了一个无参的参数时,该构造函数会因为缺省值传输参数,但是参数是无效的,所以再_size时就会得到长度为0,从而应发空间为0,但是会因为 string s; 这种代码的存在,空间还是需要被开辟的,所以还是需要开辟空间。

拷贝构造函数 

使用了深拷贝方式进行拷贝
string(const string& s)
{
  _str  = new char[s._capacity +1];
  strcpy(_str,s._str);
  _size = s._size;
  _capacity = s._capacity;
}

深浅拷贝相关介绍:C++ : 类的简单介绍(五)————— 拷贝构造函数 & 函数传参 & 运算符重载-CSDN博客 

析构函数 

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

成员函数:

遍历相关 

 size()

size_t size()const
{
  return _size;
}

operator[] 

根据operator[]再string内部的使用情况operator[]需要分为两种,一种是const使用的一种是非const使用的,而operator的内部情况无疑于指针的遍历。

char& operator[](size_t pos)
{
  assert(pos<_size);
  return _str[pos];
}


const char& operator[](size_t pos)const
{
  assert(pos<_size);
  return _str[pos];
}

在使用operator遍历的同时需要加上assert 进行防止越界的操作机制 

caopacity 

size_t capacity()const
{
  return _capacity;
}

迭代器 

有一种说法,迭代器本质上就是两个指针,其中begin指向字符串的首个字符,而end指向的是字符串末尾的\0位置

但是,不是所有的迭代器都是指针不过对于某些编译器的迭代器而言,它们的底层其实就是指针。

typedef char* iterator

iterator begin()
{
  return _str;
}

iterator end()
{
  return _str+size;
}


-------------------------------------
同时迭代器也分const使用 和 非const使用
-------------------------------------

typedef const char* const_iterator

const_iterator begin()const
{
  return _str;
}

const_iterator end()const
{
  return _str+size;
}
范围for 

围for的本质其实也是一个迭代器,只不过使用了auto进行类型的识别,但在底层也是调用了迭代器

而且,如果我们手搓了迭代器,且名字只要是迭代器的名字 iterator、  begin、  end   、const_iterator 范围for就可以使用我们手搓的迭代器

但是这几者中间名字对不上那范围for就对不上,用不了,只是所以范围for就是傻傻的替换并不会灵活的变通

 插入操作

 reserve

string内部的扩容函数,因为append和push_back需要一个是否需要扩容的机制,而reserve本身就有一个机制就是比当前空间小不扩容,比当前空间大扩容。

void reserve(size_t n)
{
 
  if(n>_capacity)//扩容机制
  {
   char*tmp = new char[n+1];
//当然因为delete的问题,开辟空间需要额外开辟一个标识符进行使用,所以需要n+1
//这个n+1并不是给\0使用的而是给为了让delete辨认而多开辟的标识符使用的

   strcpy(tmp,_str);//把原来空间的内容放到新空间内部
   
   //delete的删除机制,删除原来的空间
   delete[]_str;
   _str = tmp;//指针和地址的赋予
   _capacity = n;//表名空间已经完成
  }

}

且需要使用扩容函数 new 开辟新空间,把原来空间的地址内部的数据进行拷贝,并且使用deltet释放原来的空间改变空间指针指向。

push_back 

push_back的功能是在字符串的尾部插入一个字符,并且push_back还具有扩容的功能,并且push_back的扩容功能是需要遵循二倍扩容的规则

void push_back(char ch)
{
   //进行二倍扩容
   if(_size == _capacity)//如果长度和空间大小一样就需要扩容
     {
        reserve(_capiacty == 0? 4:2*_capacity);//同时需要考虑到长度和空间大小都是0
       //但是需要插入字符,所以需要进行空间的扩容
      }
  
   _str[_size] = ch;//ch表示插入的字符,_size表示插入的长度也表示需要插入的位置
   ++_size;
   _str[_size] = '\0';//在插入字符后面加上\0表示字符插入完成

}

append 

 append是在字符串尾部插入字符或者字符串,所以和push_back不同的是,它的扩容机制不能遵循二倍扩容的原则,因为如果字符串的长度过长,使用二倍的空间可能不够用,所以append扩大的空间可能需要遵循字符串的长度来扩充

void append(const char* str)
{  
   //扩容
   size_t len = strlen(str);
   if(_size + len > _capacity)//使用插入的长度和字符串长度相加 和空间大小对比
     {
         reserve(_size + len);//进行空间的扩大
      }
   
   strcpy(_str + _size , str);//在扩大空间后的原字符串尾部插入新的字符串
   _size + = len;//表名插入了字符串

}

operator + =  

 operator += 需要区分const 和非 const的对象使用

insert 

 insert 在指定位置插入字符 或者字符串,而根据insert在string内部底层的方式和效率来看,insert的底层是需要进行数据的挪动,以此达到插入字符串的操作。

同时和string的其他插入函数一样,都具有扩容的功能,以及还有判断是否越界的功能 

插入字符功能的insert:

void insert(size_t pos, char ch)
{
   assert(pos <= _size);//进行越界机制的断言
   
   if(_size == _capacity)//判断是否需要扩容操作
   { 
     reserve(_capacity == 0? 4:2*_capacity);
    }
  
   size_t end = _size+1;//进行底层的数据移动操作
   while(end>pos)
   {
      _str[end]  = _str[end-1];
      --end;
    }

}

erase 

在指定位置删除指定个数的字符,erase分为两种删除,同时erase的删除需要根据npos进行判断,所以需要加入前置npos ,在类之外加上 const int string::npos = -1

以及在类的成员变量中加入public的变量 static const int pos;

1.全部删除

对于全部删除满足的条件是指定删除的字符个数大于要剩下的长度或者是没有直接说明删除的字符个数,这两种情况相当于在指定位置上的字符直接变成\0

2.区间删除

区间删除,就是把这段区间后面的字符覆盖区间需要删除的空间位置,可以使用strcpy进行拷贝,把需要删除的区间的首个字符地址上传,然后把区间之后的字符串的首个字符上传

完整代码:

resize 

resize分为三个情况

一:指定的长度比字符串长度小,删除多余的部分

二:指定的长度比字符串大,但是在空间大小范围内,使用\0进行填补到相对因的指定长度

三:指定的长度比字符串大,且比空间大小大,需要进行扩容,且其余的指定长度位置的范围内的空缺地方用\0填补

情况1:

情况2和情况3: 

在进入情况二和情况三之前先使用reserve进行检查,因为reserve有一个检查机制,可以检查我们指定的长度是否大于空间大小

如果比空间大则扩容进入情况三,如果比空间小则不变进入情况2,检查之后就开始情况2和情况3都有的共同操作,也就说填充\0

完整代码: 

 

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

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

相关文章

ThreadLocal在实际开发中如何使用?

在实际开发中&#xff0c;ThreadLocal 是一个非常有用的工具&#xff0c;用于解决多线程环境下数据隔离和线程上下文数据的问题。以下是一个关于 ThreadLocal 在实际开发中使用的详细讲解&#xff0c;包括其工作原理、应用场景和实战例子。 1. 工作原理 ThreadLocal 类…

Mybatis从入门到CRUD到分页到日志到Lombok到动态SQL再到缓存

Mybatis 入门 1.导入maven依赖 <dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>x.x.x</version> </dependency>2.配置核心文件 <?xml version"1.0" encoding"U…

FISCO BCOS区块链平台上的智能合约压力测试指南

引言 在当今的分布式系统中&#xff0c;区块链技术因其去中心化、安全性和透明性而备受关注。随着区块链应用的不断扩展&#xff0c;对其性能和稳定性的要求也越来越高。因此&#xff0c;对区块链网络进行压力测试显得尤为重要。 目录 引言 1. 配置FISCO BCOS节点 2. 安装和…

Linux内核源码分析(强烈推荐收藏!)

一&#xff0c;前言 Linux内核是一个操作系统&#xff08;OS&#xff09;内核&#xff0c;本质上定义为类Unix。它用于不同的操作系统&#xff0c;主要是以不同的Linux发行版的形式。Linux内核是第一个真正完整且突出的免费和开源软件示例。Linux 内核是第一个真正完整且突出的…

Mysql - is marked as crashed and should be repaired

概述 上周发生了一个Mysql报错的问题&#xff0c;今天有时间整理一下产生的原因和来龙去脉&#xff0c;Mysql的版本是5.5,发生错误的表存储引擎都是MyISAM,产生的报错信息是Table xxxxxx is marked as crashed and should be repaired。 定位问题 产生的后果是Nginx服务没有…

MT6771 android13 自定义背光曲线

一. Android系统源码中的参数配置 MTK6771平台自己重写了背光曲线的参数&#xff0c;路径在s0_vnd/vendor/mediatek/proprietary/packages/overlay/vendor/FrameworkResOverlayExt/brightness_adaptive_support/res/values/config.xml 不过MTK的其他平台可能不是在这个路径 来看…

Linux Ubuntu部署SVN服务端结合内网穿透实现客户端公网访问

文章目录 前言1. Ubuntu安装SVN服务2. 修改配置文件2.1 修改svnserve.conf文件2.2 修改passwd文件2.3 修改authz文件 3. 启动svn服务4. 内网穿透4.1 安装cpolar内网穿透4.2 创建隧道映射本地端口 5. 测试公网访问6. 配置固定公网TCP端口地址6.1 保留一个固定的公网TCP端口地址6…

WordPress建站入门教程:如何上传安装WordPress主题?

我们成功搭建WordPress网站后&#xff0c;默认使用的是自带的最新主题&#xff0c;但是这个是国外主题&#xff0c;可能会引用一些国外的资源文件&#xff0c;所以为了让我们的WordPress网站访问速度更快&#xff0c;强烈建议大家使用国产优秀的WordPress主题。 今天boke112百…

javascript中字符串处理,常用的方法汇总

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;前端泛海 景天的主页&#xff1a;景天科技苑 文章目录 字符串对象的的相关方法1.获取字符串长度 length2.通过索引获取元素 …

让娃学习效率更高的“可视化”时间管理器

如果要问&#xff0c;老母亲在娃开学后&#xff0c;蕞着急孩子哪一种坏习惯&#xff0c;那时间管理肯定榜上有名&#xff01; 做作业的时候&#xff0c;才写了5分钟&#xff0c;已经没有耐心了&#xff0c;东摸摸西看看&#xff0c;一会说肚子疼想上厕所&#xff0c;一会又拿出…

Linux中线程的实现,线程的接口相关函数pthread_create、pthread_join、pthread_exit

目录 一.线程的概念 二.操作系统中线程的实现 三.Linux中线程的实现 四.进程与线程的区别 五.线程的接口相关函数 5.1 pthread_create 5.2 pthread_join 5.3 pthread_exit 六.代码演示 七.如何解决上述问题&#xff1f; 方案1. 方案2. 方案3. 一.线程的概念 进程是…

【数据结构】矩阵的压缩存储

矩阵的压缩存储 5.1 普通矩阵的存储 用二维数组存储 分为行优先和列优先&#xff1a; 行优先&#xff1a;优先存放一行的数据。 列优先&#xff1a;优先存放一列的数据。 注意下标是从0还是1开始的&#xff01; 5.2 对称矩阵的存储 对称矩阵定义 若n阶方阵中任意一个元素 a i …

Allure小白下载安装

1、下载官网地址&#xff1a;https://github.com/allure-framework/allure2/releases 2、下载安装包后需要解压到一个非中文名称路径下 3、配置环境变量 D:\Allure\allure-2.27.0\bin 我的电脑右键选择属性&#xff0c;高级系统设置&#xff0c;环境变量 4、CMD查看安装all…

Java | Java的输入与输出

文章目录 Java输出1、System.out.println()2、System.out.printf()3、System.out.print() Java输入1、使用Scanner类的对象获取输入&#xff08;1&#xff09;一般类型输入&#xff08;2&#xff09;字符串类型输入&#xff08;3&#xff09;char类型输入 2、使用System.in.rea…

挑战杯 基于深度学习的目标检测算法

文章目录 1 简介2 目标检测概念3 目标分类、定位、检测示例4 传统目标检测5 两类目标检测算法5.1 相关研究5.1.1 选择性搜索5.1.2 OverFeat 5.2 基于区域提名的方法5.2.1 R-CNN5.2.2 SPP-net5.2.3 Fast R-CNN 5.3 端到端的方法YOLOSSD 6 人体检测结果7 最后 1 简介 &#x1f5…

Android APP性能指标(二)

文章目录 一、响应时间1.1 数据获取1.2 响应时间指标测试点1.3 启动速度测试点1.4 响应时间测试解决方法 二、流量2.1 数据获取2.2 流量测试关注点2.3 测试标准 三、电量3.1 连接手机3.2 数据获取3.3 获取APP的UID3.3 重置电池数据收集数据3.4 电量指标测试 四、温度五、性能测…

Pyaudio的安装以及报错解决

Pyaudio是一个可以用麦克风录入声音的库&#xff0c;但我在安装时发现无论是在cmd中pip安装还是在Pycharm中安装&#xff0c;都会报一堆错误。因此写一篇我最终的解决方案&#xff0c;我的解决办法是采用离线安装的方式&#xff0c;安装pyaudio库。 一.下载离线安装包 离线安…

超详细——动态内存分配+柔性数组

☃️个人主页&#xff1a;fighting小泽 &#x1f338;作者简介&#xff1a;目前正在学习C语言和数据结构 &#x1f33c;博客专栏&#xff1a;C语言学习 &#x1f3f5;️欢迎关注&#xff1a;评论&#x1f44a;&#x1f3fb;点赞&#x1f44d;&#x1f3fb;留言&#x1f4aa;&am…

意外之失:不小心删除的文件如何寻回?

一、瞬间消失的珍贵记忆 在我们的日常电脑使用中&#xff0c;总有一些时刻让人心惊胆战——那就是不小心删除了重要的文件。或许是一个珍藏多年的照片集&#xff0c;或许是一个即将完成的项目文档&#xff0c;这些文件承载着我们的回忆、努力和成果&#xff0c;却在一次疏忽之…

文本溢出隐藏 显示省略号,鼠标悬浮展示 el-tooltip(TooltipIsShowMixin封装)

目录 mixins 封装使用 TooltipIsShowMixin效果展示 mixins 封装 TooltipIsShowMixin.js export const TooltipIsShowMixin {data() {return {tooltipIsShow: false}},methods: {tooltipIsDisHandler(className) {this.$nextTick(() > {const dom document.querySelector…
最新文章