当前位置: 首页 > news >正文

【C++】string的模拟实现

目录

一、string基本结构

1、类成员变量:

二、string构造:

1、构造函数:

2、拷贝构造:

3、析构函数:

三、string增删查改

1、reserve扩容:

2、resize扩容:

3、push_back:

4、append:

5、insert:

6、erase:

7、find:

8、substr:

四: = 运算符的重载:

1、直接实现:

​编辑

2、通过swap函数实现:


一、string基本结构

1、类成员变量:

class string
{
private:size_t _size;size_t _capacity;char* _str;
public:static size_t npos;
}

二、string构造:

1、构造函数:

string(const char* str = ""):_size(strlen(str)) //strlen \0 就是0, _capacity(strlen(str)) //strlen \0 就是0, _str(new char[_capacity + 1]) //0+1就是1
{//strcpy(_str, str);//把 \0 拷贝过去了memcpy(_str, str, _size + 1);
}

在如上代码中:形参那里的缺省参数给""即可,这个常量字符串最后会有默认的一个‘\0’

2、拷贝构造:

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

在赋值中,是通过创建一个另外的空间,在进行拷贝返回,是通过深拷贝完成的

3、析构函数:

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

三、string增删查改

1、reserve扩容:

将字符串容量调整为计划的大小更改,长度不超过 n 个字符。

如果 n 大于当前字符串容量,则该函数会导致容器将其容量增加到 n 个字符。
此函数对字符串长度没有影响,并且不能更改其内容。

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

这个就仅仅是对_str进行扩容操作,这个是开辟另一块空间,将原来的_str释放,再将_str指过去。

2、resize扩容:

将字符串的大小调整为 n 个字符的长度,

如果 n 小于当前字符串长度,则当前值将缩短为其前 n 个字符,并删除第 n 个字符之外的字符。

如果 n 大于当前字符串长度,则通过在末尾插入所需数量的字符来扩展当前内容,以达到 n 的大小。如果指定了字符ch,则新元素将初始化为 ch 否则,初始化为'\0'

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

3、push_back:

这个是在字符串后面进行增加一个字符,

思路:

首先进行判断是否扩容,再将_size的位置改为所要增加的字符,对size++后再加上\0

void push_back(char ch)
{if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size] = ch; _size++; _str[_size] = '\0';
}

4、append:

这个是在字符串后面进行增加一个字符串,

思路:

首先将要增加的字符串进行计算长度,根据长度判断是否扩容,再memcpy从_size处后len+1个,这个+1是给\0的。

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

5、insert:

在紧挨着 pos 指示的字符中插入其他字符或字符串:

思路:

首先进行判断扩容,之后将pos后的数据挪动过去,最后在插入数据

void insert(size_t pos, const char* str)
{assert(pos <= _size);size_t len = strlen(str);//扩容if (_size + len > _capacity){reserve(_size + len);}//挪动数据size_t end = _size;while (end >= pos && end != npos){_str[end + len] = _str[end];--end;}//插入数据strncpy(_str + pos, str, len);_size += len;
}

6、erase:

在pos位置向后删除len个字符串:

void erase(size_t pos, size_t len = npos)
{assert(pos <= _size);if (len == npos || pos + len >= _size){_str[pos] = '\0';_size = pos;_str[_size] = '\0';}else{size_t end = pos + len;while (end <= _size){_str[pos++] = _str[end++];}_size -= len;}
}

这里的npos就是size_t类型的,就是最大的整型值。

7、find:

在一个字符串中找一个字符,返回该字符的下标:

或者:

在一个字符串中找一个字符串,返回该字符串的首字符的下标:

size_t find(char ch,size_t pos = 0)
{assert(pos < _size);for (size_t i = pos; i < _size; i++){if (ch == _str[i]){return i;}}return npos;
}size_t find(const char* str, size_t pos = 0)
{assert(pos < _size);const char* ptr = strstr(_str, str);if (ptr){return ptr - _str;}else{return npos;}
}

8、substr:

复制子字符串,要求从指定位置开始,并具有指定的长度

string substr(size_t pos = 0, size_t len = npos)
{size_t n = len;if (len == npos || pos + len > _size){n = _size - pos;}string tmp;tmp.reserve(n);for (size_t i = pos; i < pos + n; i++){tmp += _str[i];}return tmp;
}

四: = 运算符的重载:

这个有两种写法,

分别是

自己直接实现,

或者

通过swap函数来帮忙实现:

1、直接实现:

通过深拷贝,先开辟一块赋值右边空间大1的空间(这个1是给\0的),

string& operator=(const string& s)
{if (this != &s){char* tmp = new char[s._capacity + 1];memcpy(tmp, s._str, s._size + 1);delete[] _str;_str = tmp;_size = s._size;_capacity = s._capacity;}return *this;
}

2、通过swap函数实现:

void swap(string& s)
{std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);
}string& operator=(string tmp)
{swap(tmp);return *this;
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Python | Leetcode Python题解之第330题按要求补齐数组
  • hdu7471 最优K子段(口胡题解 二分+贪心+随机化)
  • 深入探索Webkit的Web Authentication API:安全与便捷的融合
  • Flutter简介
  • 在Ubuntu 14.04上安装Git的方法
  • CentOS 7 安装详细教程
  • JavaScript高阶笔记总结(Xmind格式):第一天
  • LLM - 使用 Ollama + OpenWebUI 在 Linux 服务器中高效部署大语言模型
  • Axure移动端实例模板库,APP/小程序/H5原型模版,高保真高交互100+页
  • 【学习笔记】Day 8
  • 高职院校云计算人才培养成果导向系统构建、实施要点与评量方法
  • 网络中特殊的 IP 地址
  • 人工智能时代如何重构你的核心竞争力(程序员篇)
  • Haproxy简介及配置详解
  • 【Qt QML】ComboBox组件
  • AHK 中 = 和 == 等比较运算符的用法
  • centos安装java运行环境jdk+tomcat
  • Eureka 2.0 开源流产,真的对你影响很大吗?
  • MySQL Access denied for user 'root'@'localhost' 解决方法
  • mysql_config not found
  • sublime配置文件
  • vue2.0开发聊天程序(四) 完整体验一次Vue开发(下)
  • 分布式任务队列Celery
  • 前端技术周刊 2018-12-10:前端自动化测试
  • 让你成为前端,后端或全栈开发程序员的进阶指南,一门学到老的技术
  • 首页查询功能的一次实现过程
  • 算法-插入排序
  • 微信端页面使用-webkit-box和绝对定位时,元素上移的问题
  • 一些基于React、Vue、Node.js、MongoDB技术栈的实践项目
  • 云栖大讲堂Java基础入门(三)- 阿里巴巴Java开发手册介绍
  • 《TCP IP 详解卷1:协议》阅读笔记 - 第六章
  • 《天龙八部3D》Unity技术方案揭秘
  • UI设计初学者应该如何入门?
  • ​力扣解法汇总946-验证栈序列
  • #我与Java虚拟机的故事#连载09:面试大厂逃不过的JVM
  • $GOPATH/go.mod exists but should not goland
  • (20)目标检测算法之YOLOv5计算预选框、详解anchor计算
  • (55)MOS管专题--->(10)MOS管的封装
  • (javascript)再说document.body.scrollTop的使用问题
  • (Java数据结构)ArrayList
  • (pojstep1.3.1)1017(构造法模拟)
  • (附源码)springboot助农电商系统 毕业设计 081919
  • (四)事件系统
  • (学习日记)2024.01.09
  • (译)2019年前端性能优化清单 — 下篇
  • (转) Face-Resources
  • (转)可以带来幸福的一本书
  • .libPaths()设置包加载目录
  • .NET Core 网络数据采集 -- 使用AngleSharp做html解析
  • .net 使用$.ajax实现从前台调用后台方法(包含静态方法和非静态方法调用)
  • .NET/C# 编译期间能确定的相同字符串,在运行期间是相同的实例
  • .NetCore部署微服务(二)
  • .NET框架类在ASP.NET中的使用(2) ——QA
  • .NET上SQLite的连接
  • .net实现客户区延伸至至非客户区