【C++】——string(模拟实现)
文章目录
- string类构造
- string类拷贝构造
- string类析构
- string类运算符重载
- string类部分常用接口的模拟实现
这篇博客中构造、拷贝构造、析构、还有一些短小频繁调用的函数就不用做函数和定义分离,因为在类中,这种函数会默认是内联函数
string类构造
构造函数有一些容易忽略的细节,我会在下面的代码注释中说明
#include<iostream>
#include<assert.h>
#include<string.h>
using namespace std;
namespace sg
{class string{public:string()//:_str(nullptr) // 不能这么写,因为当我string对象为空,程序解引用到\0才会终止,遇不到就会崩溃:_str(new char[1]{'\0'}) // 空间里至少要有一个字符, _size(0), _capacity(0){}//构造函数string(const char* str){_size = strlen(str);_capacity = strlen(str);_str = new char[strlen(str) + 1];strcpy(_str, str);}private:char* _str;size_t _size;size_t _capacity;};void test_string1();}
还有另一种写法,不用初始化,直接在构造函数的参数给上缺省值
/*string():_str(new char[1]{'\0'}), _size(0), _capacity(0)
{}*/
//构造函数
//string(string(const char* str = nullptr)
// 如果参数又给空,程序还是会崩,C语言规定常量字符串后面都会有\0,所以直接给空字符串就行
string(const char* str = "")
{_size = strlen(str);_capacity = strlen(str);_str = new char[strlen(str) + 1];strcpy(_str, str);
}
string类拷贝构造
如果使用默认拷贝构造,会引发浅拷贝问题,就是当两个对象指向同一块资源时,释放资源后,会导致一块资源被析构两次,程序会报错。所以自己写一个深拷贝最好
//拷贝构造函数
//s2(s1)
string(const string& s)// this就是s2
{_str = new char[s._capacity + 1]; // 开一个和s1一样大的空间strcpy(_str, s._str); _size = s._size;_capacity = s._capacity;
}
string类析构
string的析构和c语言栈实现中的销毁栈大差不差,如果有疑问可以参考这一篇博客
C语言栈和队列
//析构函数
~string()
{if (_str) //检查一下_str是否为空,如果为空就不用再释放空间了{delete[] _str;_str = nullptr;_size = _capacity = 0;} }
string类运算符重载
string.h
char& operator[](size_t pos)
{assert(pos < _size);return _str[pos];
}
const char& operator[](size_t pos) const
{assert(pos < _size);return _str[pos];
}
string.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include "practice-string.h"
namespace sg
{void test_string1(){string s1;string s2("hello world");cout << s1.c_str() << endl;cout << s2.c_str() << endl;for (size_t i = 0; i < s2.size(); i++){s2[i] += 2;}for (auto e : s2){cout << e << " ";}cout << endl;cout << s2.c_str() << endl;}
}
我通过测试,发现并不能用范围for遍历,报错显示未找到匹配的begin函数,需要我们自己实现
范围for看着很方便,但本质就是迭代器,迭代器模拟的是指针的行为,所以我们返回原生指针即可
string.h
typedef char* iterator;
typedef char* const_iterator;
iterator begin()
{return _str;
}
iterator end()
{return _str + _size;
}
const_iterator begin() const
{return _str;
}const_iterator end() const
{return _str + _size;
}
赋值运算符
string operator=(const string& s)
{if (this != &s)//地址相同,就是自己赋值给自己{delete[] _str;_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}return *this;
}
string类部分常用接口的模拟实现
string.h
#pragma once
#include<iostream>
#include<assert.h>
#include<string.h>
using namespace std;
namespace sg
{class string{public:typedef char* iterator;typedef char* const_iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}const_iterator begin() const{return _str;}const_iterator end() const{return _str + _size;}/*string():_str(new char[1]{'\0'}), _size(0), _capacity(0){}*///构造函数string(const char* str = ""){_size = strlen(str);_capacity = strlen(str);_str = new char[strlen(str) + 1];strcpy(_str, str);}//析构函数~string(){delete[] _str;_str = nullptr;_size = _capacity = 0;}//拷贝构造函数//s2(s1)string(const string& s){_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}const char* c_str() const{return _str;}size_t size() const{return _size;}char& operator[](size_t pos){assert(pos < _size);return _str[pos];}const char& operator[](size_t pos) const{assert(pos < _size);return _str[pos];}// s2 = s1// s1 = s1string operator=(const string& s){if (this != &s)//地址相同,就是自己赋值给自己{delete[] _str;_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}return *this;}void clear(){_str[0] = '\0';_size = 0;}void reserve(size_t n);void push_back(char ch);void append(const char* str);string& operator+=(char ch);string& operator+=(const char* str);void insert(size_t pos, char ch);void insert(size_t pos, const char* str);void erase(size_t pos, size_t len = npos);size_t find(char ch, size_t pos = 0);size_t find(const char* str, size_t pos = 0);string substr(size_t pos = 0, size_t len = npos);private:char* _str;size_t _size;size_t _capacity;static const size_t npos;};void test_string1();void test_string2();bool operator<(const string& s1, const string& s2);bool operator<=(const string& s1, const string& s2);bool operator>(const string& s1, const string& s2);bool operator>=(const string& s1, const string& s2);bool operator!=(const string& s1, const string& s2);bool operator==(const string& s1, const string& s2);ostream& operator<<(ostream& out, const string& s);istream& operator>>(istream& in, string& s);
}
string.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include"string.h"
namespace sg
{const size_t string::npos = -1;//声明和定义分离void string::reserve(size_t n){if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}}void string::push_back(char ch){if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size] = ch;++_size;_str[_size] = '\0';}string& string::operator+=(char ch){push_back(ch);return *this;}void string::append(const char* str){size_t len = strlen(str);if (_size + len > _capacity){//大于二倍,需要多少开多少,小于二倍,就按二倍扩reserve(_size + len > 2 * _capacity ? _size + len : 2 * _capacity);}strcpy(_str + _size, str);//从\0开始拷贝,\0会自动被挤到后面_size += len;}string& string::operator+=(const char* str){append(str);return *this;}void string::insert(size_t pos, char ch){assert(pos < _size);if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}//挪动数据/*size_t end = _size;while (end >= pos){_str[end + 1] = _str[end];--end;}*///挪动数据size_t end = _size + 1;while (end > pos){_str[end] = _str[end - 1];--end;}//挪动完数据后再插入_str[pos] = ch;++_size;}void string::insert(size_t pos, const char* str){assert(pos < _size);if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}size_t len = strlen(str);size_t end = _size + len;while (end >= pos + len){_str[end] = _str[end - len];--end;}for (size_t i = 0; i < len; i++){_str[pos + i] = str[i];}_size += len;}void string::erase(size_t pos, size_t len){if (len >= _size - pos){_str[pos] = '\0';_size = pos;}else{for (size_t i = pos + len; i <= _size; i++){_str[i - len] = _str[i];}_size -= len;}}size_t string::find(char ch, size_t pos){assert(pos < _size);for (size_t i = pos; i < _size; i++){if (_str[i] == ch){return i;}}return npos;}size_t string::find(const char* str, size_t pos){assert(pos < _size);const char* ptr = strstr(_str + pos, str);if (ptr == nullptr){return npos;}else{return ptr - _str;}}string string::substr(size_t pos = 0, size_t len){assert(pos < _size);if (len > _size - pos){len = _size - pos;}string sub;sub.reserve(len);for (size_t i = 0; i < len; i++){sub += _str[pos + i];}return sub;}bool operator<(const string& s1, const string& s2){return strcmp(s1.c_str(), s2.c_str()) < 0;}bool operator<=(const string& s1, const string& s2){return s1 == s2 || s1 < s2;}bool operator>(const string& s1, const string& s2){return !(s1 <= s2);}bool operator>=(const string& s1, const string& s2){return !(s1 < s2);}bool operator!=(const string& s1, const string& s2){return !(s1 == s2);}bool operator==(const string& s1, const string& s2){return strcmp(s1.c_str(), s2.c_str()) == 0;}ostream& operator<<(ostream& out, const string& s){for (auto ch : s){out << ch;}return out;}istream& operator>>(istream& in, string& s){s.clear();//创造一块缓冲const int N = 256;char buffer[N];int i = 0;char ch;ch = in.get();while (ch != ' ' && ch != '\0'){buffer[i++] == ch;if (i == N - 1)// buffer条件{buffer[i] = '\0';s += buffer;i = 0;}if (i > 0){buffer[i] = '\0';s += buffer;}return in;}}void test_string1(){string s1;string s2("hello world");cout << s1.c_str() << endl;cout << s2.c_str() << endl;for (size_t i = 0; i < s2.size(); i++){s2[i] += 2;}cout << s2.c_str() << endl;}void test_string2(){string s1("hello world");s1 += '!';s1 += '#';cout << s1.c_str() << endl;s1 += "renqing";cout << s1.c_str() << endl;s1.insert(0, '#');cout << s1.c_str() << endl;string s2("hello world");s2.insert(5, "big");cout << s2.c_str() << endl;s2.erase(5, 3);cout << s2.c_str() << endl;}}
test.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include"string.h"
int main()
{//sg::test_string1();sg::test_string2();return 0;
}
相关文章:
【C++】——string(模拟实现)
文章目录 string类构造string类拷贝构造string类析构string类运算符重载string类部分常用接口的模拟实现 这篇博客中构造、拷贝构造、析构、还有一些短小频繁调用的函数就不用做函数和定义分离,因为在类中,这种函数会默认是内联函数 string类构造 构造函…...
c++20 std::format 格式化说明
在标头<format>定义 ()功能很强大,它把字符串当成一个模板,通过传入的参数进行格式化,并且使用大括号‘{}’作为特殊字符代替‘%’。 1、基本用法 (1)不带编号,即“{}”(2)带…...
HTB-Unified(log4j2漏洞、MongoDb替换管理员密码)
前言 各位师傅大家好,我是qmx_07,今天给大家讲解Unified靶机 渗透过程 信息搜集 服务器开放了SSH服务,HTTP服务 访问网站 验证log4j2漏洞 8443端口:UniFi 网络 ,访问查询 是否有Nday漏洞利用 可以观察到UniFi的版…...
每天五分钟深度学习PyTorch:不同的神经网络层设置不同的学习率
本文重点 我们前面学习了基本网络模型的搭建,获取网络模型的子结构,以及优化器optim,我们发现我们设置优化器的时候,是对整个模型设置的,也就是说整个模型的参数学习率是一样,本节课程我们学习如何给不同的网络层设置不同的学习率。主要还是通过优化器optim来实现的,本…...
【渗透测试】——DVWA靶场搭建
📖 前言:DVWA(Damn Vulnerable Web Application)是一个用于安全漏洞测试的 PHP/MySQL 网络应用,旨在为安全专业人士提供一个合法的环境,以测试他们的技能和工具,同时帮助 Web 开发者更好地理解 …...
国内人工智能产业发展现状及对策研究
一、引言 人工智能作为新时代科技革命和产业变革的核心力量,正深刻改变着全球经济格局。我国政府高度重视人工智能产业发展,将其列为国家战略性新兴产业。在此背景下,本文旨在分析我国人工智能产业发展现状,探讨面临的挑战&#x…...
完整版订单超时自动取消功能
前几天对实习还是继续学习技术产生了抉择,问了一个前辈,他抛给我一个问题,怎么做15分钟订单自动取消,我说然后到时间之后,自动执行这个订单关闭业务,比如把锁了的库存给解开等等操作,然后在数据…...
算法刷题:300. 最长递增子序列、674. 最长连续递增序列、718. 最长重复子数组、1143. 最长公共子序列
300. 最长递增子序列 1.dp定义:dp[i]表示i之前包括i的以nums[i]结尾的最长递增子序列的长度 2.递推公式:if (nums[i] > nums[j]) dp[i] max(dp[i], dp[j] 1); 注意这里不是要dp[i] 与 dp[j] 1进行比较,而是我们要取dp[j] 1的最大值…...
go 笔记
数据结构与 方法(增删改查) 安装goland,注意版本是2024.1.1,不是2024.2.1,软件下载地址也在链接中提供了 ‘go’ 不是内部或外部命令,也不是可运行的程序 或批处理文件。 在 Windows 搜索栏中输入“环境变量”&#…...
路由等保测评
1.身份鉴别 应对登录的用户进行身份标识和鉴别, 身份标识具有唯一性,身份鉴别信息具有复杂度要求并定期更换。 可以使用“ service password-encryption"命令对存储在配置文件中的所有口令和类似数据进行加密, 以避免攻击者通过读取配…...
C# 反射之动态生成dll/exe
这个可能应该属于反射的高级使用范围了,平常在项目中使用的人估计也不是很多。由于使用反射的话会降低性能,比如之前用到的GetValue、SetValue等之类,但是使用这种方式会大大提高效率,在这里我只想说,都直接写IL指令了…...
Rust 所有权 Slices
文章目录 发现宝藏1. Slice 的基础知识1.1 什么是 Slice?1.2 如何创建 Slice? 2. 处理字符串 Slice2.1 字符串的 Slice2.2 字符串的 Unicode 和切片 3. 在函数中使用 Slice3.1 传递 Slice 给函数3.2 可变 Slice 的函数 4. 复杂示例4.1 处理多维数组的 Sl…...
windows 安全与网络管理问题
问题:当编写的脚本或程序运行的时候,可能被windows阻止访问网络甚至被删除 避免被删除 wini 进入设置界面 -> 选择更新与安全 -> 选择windwos defender -> 点击添加排除项,将指定的文件或目录排除,避免被软件删除 允许…...
基于Python实现一个庆祝国庆节的小程序
功能: 添加互动功能:允许用户选择不同的祝福语或者查询不同的国庆节信息。动态背景音乐:播放国庆节相关的背景音乐。增加节日小测验:提供一些关于国庆节的趣味小测验,让用户参与。增强图形用户界面 (GUI):…...
Anaconda 安装与使用教程
Anaconda 安装与使用教程 介绍 Anaconda 是一个用于科学计算的 Python 和 R 的发行版,它包含了众多流行的科学计算、数据分析、机器学习等领域的库。本教程旨在帮助初学者快速上手 Anaconda,并学会如何使用其管理环境以及安装包。 第一步:…...
时序预测SARIMAX模型
1. 项目背景 本文基于kaggle平台相关竞赛项目,具体连接如下: Time Series Forecasting With SARIMAX 基本信息如内容说明、数据集、已提交代码、当前得分排名以及比赛规则等,如图【1】所示,可以认真阅读。 图 1 2. 数据读取 …...
gin集成jaeger中间件实现链路追踪
1. 背景 新业务线带来新项目启动,需要改进原有项目的基础框架和组件能力,以提升后续开发和维护效率。项目搭建主要包括技术选型、框架搭建、基础服务搭建等。这其中就涉及到链路追踪的内容,结合其中的踩坑情况,用一篇文章来说明完…...
前端层面----监控与埋点
前言: 站在产品的视角,经常会问如下几个问题: 产品有没有用户使用 用户用得怎么样 系统会不会经常出现异常 如何更好地满足用户需求服务用户 当站在技术视角时,经常会问如下几个问题: 系统出现异常的频率如何 异常…...
linux Command
linux Command 1. 系统监控命令 1.1 top top [param] top -H -p pid,查看进程pid下面的子线程。-b以处理模式操作-c显示完整的命令行而不只是显示命令名。-d 屏幕刷新间隔时间。-l 忽略失效过程。-s 保密模式。-S 累积模式。-u 【用户名】 指定用户名。-p 【进程…...
uniapp登录页面( 适配:pc、小程序、h5)
<!-- 简洁登录页面 --> <template><view class"login-bg"><image class"img-a" src"https://zhoukaiwen.com/img/loginImg/2.png"></image><image class"img-b" src"https://zhoukaiwen.com/im…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...
MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...
12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...
SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...
技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...
